問題:
非常經典的問題,將一個二叉樹遍曆,前序,中序,後序遍曆由遞迴轉換成非遞迴。
分析:
遞迴轉換成非遞迴,一般解法是自己使用棧去類比遞迴過程,首先我們來看下後序遍曆遞迴解法:
void postOrderTraverse(pNode root)
{
if(root == NULL)
return ;
postOrderTraverse(p->left);
postOrderTraverse(p->right);
visit(p);
return ;
}
從上面遞迴過程可以看出來,首先是從左子樹一直遞迴下去,知道為空白,然後從棧中返回一個節點,再從這個節點的右節點進行遍曆,最後才訪問根節點,這裡後序遍曆的非遞迴演算法,需要一個小trick,p自身需要做個標記,標記當前的右節點是否已經遍曆,如果沒有遍曆,執行右節點任務,如果已經執行,可以訪問自己。
代碼如下:
void PostTraverse(BINARYTREE p){while (p != NULL || !Stack.IsEmpty()) //存在工作(手頭或待完成) {while (p != NULL) //處理手頭工作,直到無現成手頭工作 {Stack.Push(p, RCHILD_AND_ITSELF);p = p->LChild;}if (!Stack.IsEmpty()) //是否存在待完成工作 {Stack.Pop(p, Tag);if (Tag == RCHILD_AND_ITSELF) //情況一: RChild & Itself {Stack.Push(p, ONLY_ITSELF)//儲存待完成工作 p = p->RChild; //新的手頭工作 }else //tag == ONLY_ITSELF, 情況二: Only Itself {visit(p);p = NULL; //已無現成的手頭工作 }}}}
總結:
從上面代碼可以看出,遞迴轉換成非遞迴,我們需要使用棧來類比。
用一個指標變數儲存當前執行的任務,p
用一個棧儲存將要執行的任務,Stack
如果p為NULL了,說明當前手頭沒有任務,我們需要從Stack中選擇一個任務,如果Stack為空白,說明當前所有任務都已經完成
理解了手頭任務和待完成任務,自行用棧類比就比較好理解、實現了。