1、先序的非递归
思想:先将根节点放入栈中,先入右节点,再入左节点。根据栈的原理,在访问时是左到右的。
开始时,我将push(index)这个操作放在循环里面,这是一条无限循环的不归路啊
template<class T>//非递归先序遍历,使用的是栈
void BST<T>::iterativePreorder()
{//思路:将节点放入栈中,访问之后,先放入右节点,再放入左节点。
BSTNode<T>*index=root;
Stack<BSTNode<T>*>preorderStack;
preorderStack.push(index);//当前节点入栈
while(index&&!preorderStack.isEmpty())
{
index=preorderStack.pop();
visit(index);//访问此节点
if (index->right)
{
preorderStack.push(index->right);//右节点入栈,如此出栈就是先序遍历
}
if (index->left)
{
preorderStack.push(index->left);//左节点入栈
}
}
}
2、中序遍历
首先找到最左边的节点。
中序遍历思维不要定势,采用两重循环,在里面对栈中元素进行操作。
其实在遍历中关键的是何时入栈,出栈,以及访问节点的时机
template<class T>//非递归中序遍历算法
void BST<T>::iterativeInorder()
{
//思路:使用一个栈来实现。首先遍历一个节点的左子树。退出一个,将指针重新的赋值
//刚开始打算使用一个栈,但是并没有增加第二个while,在访问了一个没有右节点的叶子节点后直接的退出
//重新的赋值于index,有没有右子树都给予包含
Stack<BSTNode<T>*>inorderStack;
BSTNode<T>* p=NULL;
BSTNode<T>* index=root;
while(index!=NULL)//可能会出现栈中元素 已经为空,而此时元素并没有访问结束
{
while(index!=NULL)
{
inorderStack.push(index);
index=index->left;
}
while(!inorderStack.isEmpty())//当栈中元素多于一个时,逐个访问栈中元素,
{
p=inorderStack.pop();
visit(p);//访问栈顶元素
if (p->right)//访问该元素的右子树
{
//p=p->right;
index=p->right;//若节点没有右子树,index为空,返回继续访问栈中下一个元素。
break;
//若有右子树,则置index为这个右子树,那么继续从右子树开始访问节点
}
//index=p; //开始采取是的是将p的值赋给index,后面发现若是已经到达最后一个节点,会无线的循环。因为index永远不会为空
}
}
}
3、后序遍历
两种方法,一个是对每个节点增添一个标志的bool值,另外一种是采用两个栈。后序遍历中若采用与前面一样的方法,我们会发现。入栈之后,查看有没有右子树,找到之后index指向这个右子树。访问这个右子树后,出栈又发现这个节点有右子树,于是陷入死循环中。这是我一开始编程犯的错误。于是我想是不是要加一个标志位,但是在程序中有必要为一个后序遍历加一个内存???我不甘,于是我继续的探讨,在一篇文章中发现后序与先序中存在的某些关系,于是发现从左到右的后序与从右到左的先序的逆序是一样的
template<class T>//非递归后序遍历算法
void BST<T>::iterativePostorder2()//利用访问标志
{
BSTNode<T>*index=root;
Stack<BSTNode<T>*>postStack;
while(index&&index->bVisit==false)//若是没有已经访问这一条件,那么整棵树无限的访问
{
while(index)
{
postStack.push(index);
index=index->left;//寻找到最左边的节点
}
while(!postStack.isEmpty())
{
index=postStack.pop();//若是没有节点直接访问,若有,那么还必须把它放入栈,因为之后还会访问
if (index->right&&(index->right->bVisit==false))//若没有已经访问这个条件,会在一棵树中的右节点与其本身不断的循环
{
postStack.push(index);//重新的将刚刚pop的节点放入栈
index=index->right;//对右子树进行操作
break;
}
else
{
index->bVisit=true;//设置访问属性
visit(index);//访问之
}
}
}
}
template<class T>
void BST<T>::iterativePostorder()//通过两个栈,从左到右后序等于从右到左的先序的逆序。
{
BSTNode<T> *index=root;
BSTNode<T> *p=root;
Stack<BSTNode<T>*>postStack;
Stack<BSTNode<T>*>postStackReverse;
postStack.push(index);
while(index&&!postStack.isEmpty())
{
index=postStack.pop();
postStackReverse.push(index);
if (index->left)//先入左,等于从右到左进行访问
{
postStack.push(index->left);
}
if (index->right)
{
postStack.push(index->right);
}
}
while(!postStackReverse.isEmpty())
{
index=postStackReverse.pop();
visit(index);
}
}
void test()
{
int testArray[]={15,5,16,3,12,20,4,10,13,18,23,6,7};
BST<int> bstTree;
cout<<"原来数组内容为"<<endl;
for (int nIndex=0;nIndex<13;nIndex++)
{
cout<<testArray[nIndex]<<" ";
bstTree.insert(testArray[nIndex]);
}
/*bstTree->preorder(bstTree->root);
bstTree->inorder(bstTree->root);
bstTree->postorder(bstTree->root);*/
cout<<endl<<"先序的非递归遍历算法结果"<<endl;
bstTree.iterativePreorder();
cout<<endl<<"中序的非递归遍历算法结果"<<endl;
bstTree.iterativeInorder();
cout<<endl<<"后序的采用已访问标志的非递归遍历算法结果"<<endl;
bstTree.iterativePostorder();
cout<<endl<<"后序的采用两个栈的非递归遍历算法结果"<<endl;
bstTree.iterativePostorder2();
}
本文介绍了二叉树的三种非递归遍历算法:先序遍历、中序遍历和后序遍历,并提供了具体的实现代码。通过栈结构实现了非递归遍历,避免了递归带来的堆栈溢出风险。
1万+

被折叠的 条评论
为什么被折叠?



