二叉樹的遞歸遍歷算法非常漂亮和易讀,但是非遞歸算法就沒那麼容易懂了,尤其是後序遍歷的非遞歸算法。
一. 前序遍歷
1 void PreOrderTraverse(Node *root) 2 { 3 stack<Node *> ns; 4 Node *n=root; 5 while(n!=NULL || !ns.empty()) 6 { 7 if(n!=NULL) 8 { 9 print(n); 10 ns.push(n); 11 n=n->pLeft; 12 } 13 else 14 { 15 ns.pop(n); 16 n=n->pRight; 17 } 18 } 19 }
二.中序遍歷
1 void InOrderTraverse(Node *root) 2 { 3 stack<Node *> ns; 4 Node *n=root; 5 while(n!=NULL || !ns.empty()) 6 { 7 if(T!=NULL) 8 { 9 ns.push(n); 10 n=n->pLeft; 11 } 12 else 13 { 14 ns.pop(n); 15 print(n); 16 n=n->pRight; 17 } 18 } 19 }
三. 後序遍歷
後序遍歷就比較麻煩了,有兩種算法。後序遍歷的關鍵是保證兒子結點先於父結點打印。
第一種:還是跟先序和中序一樣,一路往左走,找到最左的一個結點A。A不可能再有左兒子了,但可能有右兒子。而這是A第一次爲stack的top結點,但是這時還不能打印它。將A的右兒子入棧後,再次執行,待到A第二次成爲top時,這說明A右兒子結點已經處理了,因爲A結點在棧中的位置必然是在右兒子之下的。用一個變量來表示這個二次的關係。代碼如下:
1 void PostOrderTraverse(Node *root) 2 { 3 stack<Node *> ns; 4 Node *n=root; 5 while(n!=NULL || !ns.empty()) 6 { 7 if(n!=NULL) 8 { 9 n->IsFirst=true;//The first time to be the top of ns stack. 10 ns.push(n); 11 n=n->pLeft; 12 } 13 else 14 { 15 if(!ns.empty()) 16 { 17 ns.pop(n); 18 if(n->IsFirst==true)//The first time to be the top of ns stack.Don't print. 19 { 20 n->IsFirst=false; 21 ns.push(n); 22 n=n->pRight; 23 } 24 else //The second time.Print it. 25 print(n); 26 } 27 } 28 } 29 }
第二種思路:後序遍歷的順序是:左兒子->右兒子->父結點。那麼,入棧的順序就應該倒過來,即:父結點->右兒子->左兒子。當前top位置的結點如果沒有左右兒子結點或者是左右兒子結點都已經訪問過了,那麼就可以打印出來;如果不是這樣,就將右兒子和左兒子依次入棧。注意,這裏需要保存當前top位置之前的那次訪問的結點,而且root結點需要在while循環之前入棧。代碼如下:
1 void PostOrderTraverse2(Node *root) 2 { 3 stack<Node *> ns; 4 Node *n=root; 5 Node *previous=NULL;//It is NULL at first. 6 ns.push(n); 7 while(n!=NULL || !ns.empty()) 8 { 9 n=ns.top(); 10 if( (n->pLeft==NULL && n->pRight==NULL) || (previous==n->pLeft || previous==n->pRight)) 11 { 12 print(n); 13 ns.pop(); 14 previous=n; 15 } 16 else 17 { 18 if(n->pRight!=NULL) 19 ns.push(n->pRight); 20 if(n->pLeft!=NULL) 21 ns.push(n->pLeft); 22 } 23 } 24 }
參考資料:http://www.cnblogs.com/dolphin0520/archive/2011/08/25/2153720.html
如果你覺得我的文章對你有幫助,請贊一下,非常感謝!