C++编程练习(17)----“二叉树非递归遍历的实现“

来源:互联网 发布:巨人网络怎么样 知乎 编辑:程序博客网 时间:2024/05/17 22:56

二叉树的非递归遍历

最近看书上说道要掌握二叉树遍历的6种编写方式,之前只用递归方式编写过,这次就用非递归方式编写试一试。

C++编程练习(8)----“二叉树的建立以及二叉树的三种遍历方式“(前序遍历、中序遍历、后续遍历)

递归的思想也就是栈的思想,既然不用递归,那就改用栈的方式。



“递归=栈”



1、前序遍历

前序遍历按照“根结点-左孩子-右孩子”的顺序进行访问。

a)递归实现前序遍历:

void PreOrderTraverse(BiTNode *T)/*递归前序遍历*/{if (T==NULL)return;std::cout<<T->data<<"\t";PreOrderTraverse(T->lchild);PreOrderTraverse(T->rchild);}

b)非递归实现前序遍历:

对于根结点P:
1)访问结点P,并将结点P入栈;
2)判断结点P的左孩子是否为空,若为空,则取栈顶结点并进行出栈操作,并将栈顶结点的右孩子置为当前的结点P,循环至1);若不为空,则将P的左孩子置为当前的结点P;
3)直到P为NULL并且栈为空,则遍历结束。

void nPreOrderTraverse(BiTNode *T)/*非递归前序遍历*/{if (T==NULL)return;BiTNode *p;p = T;std::stack<BiTNode*> stk;while(p!=NULL||!stk.empty()){while(p!=NULL){std::cout<<p->data<<"\t";stk.push(p);p = p->lchild;}if(!stk.empty()){p = stk.top();stk.pop();p = p->rchild;}}}

2、中序遍历

中序遍历按照“左孩子-根结点-右孩子”的顺序进行访问。

a)递归实现中序遍历

void InOrderTraverse(BiTNode *T)/*递归中序遍历*/{if (T==NULL)return;InOrderTraverse(T->lchild);std::cout<<T->data<<"\t";InOrderTraverse(T->rchild);}

b)非递归实现中序遍历

对于根结点P:
1)若其左孩子不为空,则将P入栈并将P的左孩子置为当前的P,然后对当前结点P再进行相同的处理;
2)若其左孩子为空,则取栈顶元素并进行出栈操作,访问该栈顶结点,然后将当前的P置为栈顶结点的右孩子;
3)直到P为NULL并且栈为空则遍历结束。

void nInOrderTraverse(BiTNode *T)/*非递归中序遍历*/{if(T==NULL)return;std::stack<BiTNode*> stk;BiTNode* p;p = T;while(p!=NULL || !stk.empty()){while(p!=NULL){stk.push(p);p = p->lchild;}if(!stk.empty()){p = stk.top();stk.pop();std::cout<<p->data<<"\t";p = p->rchild;}}}

3、后序遍历

后序遍历按照“左孩子-右孩子-根结点”的顺序进行访问。

a)递归实现后序遍历

void PostOrderTraverse(BiTNode *T)/*递归后序遍历*/{if(T==NULL)return;PostOrderTraverse(T->lchild);PostOrderTraverse(T->rchild);std::cout<<T->data<<"\t";}

b)非递归实现后序遍历

这里实现略复杂,当初想出来的方法过于笨重,后参考http://www.cnblogs.com/dolphin0520/archive/2011/08/25/2153720.html,改写如下:

要保证根结点在左孩子和右孩子访问之后才能访问,因此对于任一结点P,先将其入栈。如果P不存在左孩子和右孩子,则可以直接访问它;或者P存在左孩子或者右孩子,但是其左孩子和右孩子都已被访问过了,则同样可以直接访问该结点。若非上述两种情况,则将P的右孩子和左孩子依次入栈,这样就保证了每次取栈顶元素的时候,左孩子在右孩子前面被访问,左孩子和右孩子都在根结点前面被访问。

对于根结点P:

1)将P入栈,设置当前结点 cur

2)将当前的 cur 置为栈顶结点,如果 cur 不存在左孩子和右孩子,或者 cur 存在左孩子或者右孩子,但是其左孩子和右孩子都已被访问过了,则可以直接访问该结点并进行出栈操作。否则将 cur 的右孩子和左孩子依次入栈;

3)直到栈为空则遍历结束。

void nPostOrderTraverse(BiTNode *T)/*非递归后序遍历*/{if(T==NULL)return;BiTNode* cur;/*当前结点*/BiTNode* pre = NULL;/*前一次输出的结点*/std::stack<BiTNode*> stk;stk.push(T);while(!stk.empty()){cur = stk.top();if((cur->lchild==NULL && cur->rchild==NULL) ||(pre!=NULL && (cur->lchild==pre || cur->rchild==pre))){/*如果当前结点没有孩子结点或者孩子节点都已被访问过*/std::cout<<cur->data<<"\t";stk.pop();pre = cur;}else{if(cur->rchild!=NULL)stk.push(cur->rchild);if(cur->lchild!=NULL)stk.push(cur->lchild);}}}

4、完整测试代码

1)BiTree.h头文件

/* BiTree.h头文件 */#include<iostream>#include<stack>typedef char TElemType;class BiTNode{/*创建结点类,使用的是左右孩子表示法*/public:BiTNode():data(0),lchild(NULL),rchild(NULL){}TElemType data;BiTNode *lchild,*rchild;};void CreateBiTree(BiTNode **T)/*二叉树的建立,这里形参用的是双指针,需要注意*/{/*这里输入的是一个扩展二叉树,每个结点若有空指针,*/TElemType ch;/*则将其值设为一个特定值,本代码中是'#'*/std::cin>>ch;std::cin.clear();if(ch=='#')*T=NULL;else{*T=new BiTNode;if(!*T)exit(1);(*T)->data=ch;CreateBiTree(&(*T)->lchild);CreateBiTree(&(*T)->rchild);}}void PreOrderTraverse(BiTNode *T)/*递归前序遍历*/{if (T==NULL)return;std::cout<<T->data<<"\t";PreOrderTraverse(T->lchild);PreOrderTraverse(T->rchild);}void nPreOrderTraverse(BiTNode *T)/*非递归前序遍历*/{if (T==NULL)return;BiTNode *p;p = T;std::stack<BiTNode*> stk;while(p!=NULL||!stk.empty()){while(p!=NULL){std::cout<<p->data<<"\t";stk.push(p);p = p->lchild;}if(!stk.empty()){p = stk.top();stk.pop();p = p->rchild;}}}void InOrderTraverse(BiTNode *T)/*递归中序遍历*/{if (T==NULL)return;InOrderTraverse(T->lchild);std::cout<<T->data<<"\t";InOrderTraverse(T->rchild);}void nInOrderTraverse(BiTNode *T)/*非递归中序遍历*/{if(T==NULL)return;std::stack<BiTNode*> stk;BiTNode* p;p = T;while(p!=NULL || !stk.empty()){while(p!=NULL){stk.push(p);p = p->lchild;}if(!stk.empty()){p = stk.top();stk.pop();std::cout<<p->data<<"\t";p = p->rchild;}}}void PostOrderTraverse(BiTNode *T)/*递归后序遍历*/{if(T==NULL)return;PostOrderTraverse(T->lchild);PostOrderTraverse(T->rchild);std::cout<<T->data<<"\t";}void nPostOrderTraverse(BiTNode *T)/*非递归后序遍历*/{if(T==NULL)return;BiTNode* cur;/*当前结点*/BiTNode* pre = NULL;/*前一次输出的结点*/std::stack<BiTNode*> stk;stk.push(T);while(!stk.empty()){cur = stk.top();if((cur->lchild==NULL && cur->rchild==NULL) ||(pre!=NULL && (cur->lchild==pre || cur->rchild==pre))){/*如果当前结点没有孩子结点或者孩子节点都已被访问过*/std::cout<<cur->data<<"\t";stk.pop();pre = cur;}else{if(cur->rchild!=NULL)stk.push(cur->rchild);if(cur->lchild!=NULL)stk.push(cur->lchild);}}}

2)main文件

#include"BiTree.h"using namespace std;int main(){BiTNode *T=new BiTNode;std::cout<<"请前序遍历输入各节点:";CreateBiTree(&T);cout<<"\n该树的前序遍历输出为:"<<endl;PreOrderTraverse(T);cout<<endl;nPreOrderTraverse(T);cout<<"\n该树的中序遍历输出为:"<<endl;InOrderTraverse(T);cout<<endl;nInOrderTraverse(T);cout<<"\n该树的后序遍历输出为:"<<endl;PostOrderTraverse(T);cout<<endl;nPostOrderTraverse(T);cout<<endl;return 0;}

5、测试结果



1 0
原创粉丝点击