二叉树的三种遍历方法实现
二叉树是比较经典的数据结构,而遍历则是树最基本的操作。有先序遍历,中序遍历,后序遍历,先后针对的是根节点。
树本身就是递归定义,因此使用递归来实现三种遍历很容易。
int PreOrderTraverse(IDTree* tree) { if(tree != NULL) { cout << tree->val << endl; PreOrderTraverse(tree->pLef); PreOrderTraverse(tree->pRig); return 0; } else return 1; } int MidOrderTraverse(IDTree* tree) { if(tree == NULL)return 1; else { MidOrderTraverse(tree->pLef); cout << tree->val << endl; MidOrderTraverse(tree->pRig); } } int PostOrderTraverse(IDTree* tree) { if(tree == NULL) return 1; else { PostOrderTraverse(tree->pLef); PostOrderTraverse(tree->pRig); cout << tree->val << endl; } }
以上是递归法遍历树的简单实现。
优点:简单易读,思路清晰,能很快写出来。
缺点:要使用栈空间保存现场,递归太深容易造成栈空间溢出。
所有的递归程序都能改成非递归的,树的遍历也是,可以利用栈数据结构来完成递归的作用,为了简单使用stl中的stack。
先序和中序如下:
int PreOrderNoRecurse2(IDTree* tree) { IDTree* pt = tree; stack<IDTree* > st; while(pt!=NULL || !st.empty()) { while(pt!=NULL) { cout << pt->val << endl;; st.push(pt); pt = pt->pLef; } if(!st.empty()) { pt= st.top(); st.pop(); pt = pt->pRig; } } return 1; } int MidOrderNoRecurse(IDTree* tree) { stack<IDTree*> st; IDTree* ptr = tree; IDTree* tmp = NULL; while( ptr !=NULL || !st.empty() ) { while(ptr != NULL) { st.push(ptr); ptr = ptr->pLef; } if(!st.empty()) { ptr = st.top(); cout << ptr->val << endl; st.pop(); ptr = ptr->pRig; } } return 1; }
不好写的是后序遍历,因为右子树要在根之前遍历,左右子树遍历完才能遍历根节点。
以下是参考了http://www.cnblogs.com/ybwang/archive/2011/10/04/lastOrderTraverse.html这位大神的代码,稍微修改后的版本:
class SNode{ public: IDTree * p; int rvisited; SNode(IDTree* ptr=NULL, int rv=0) { p= ptr; rvisited = rv; } ~SNode(){} } ;
1 int lastOrderTraverse(IDTree* p) 2 { 3 stack<SNode> snode; 4 SNode sn; 5 IDTree* bt = p; 6 IDTree* tmp; 7 while(bt) 8 { 9 snode.push(SNode(bt, 0)); 10 bt = bt->pLef; 11 } 12 while(!snode.empty()) 13 { 14 sn = snode.top(); 15 if(!sn.p->pRig || sn.rvisited) 16 { 17 tmp = snode.top().p; 18 snode.pop(); 19 visit(tmp); 20 } 21 else 22 { 23 sn.rvisited = 1; 24 snode.pop(); 25 snode.push(sn); 26 tmp = sn.p->pRig; 27 while(tmp != 0) 28 { 29 snode.push(SNode(tmp, 0)); 30 tmp = tmp->pLef; 31 } 32 } 33 } 34 return 1; 35 }
增加一个栈元素SNode,存储的是节点指针和节点的右子树是否被访问过。
以上后序遍历的主要思路是先从根节点出发一直沿着左子树向下到头,此时如果最下面的节点(没有左子树)没有右子树或者右子树被访问过了,那么我们可以访问这个节点了,访问完成后将该节点pop出栈。之后继续从取栈顶元素,如果右子树则将rvisited置为1,然后从它的右子树往下沿着左子树遍历到头继续重复开始的步骤。
learn++