眾多周知,對於二叉樹的遍歷, 一種比較容易理解以及編寫的方式就是遞歸的方式了,下面針對二叉樹遍歷的中序遍歷做一個簡單的分析:
void travelTree(BiTree T, int deep){ if (T->lchild != NULL) travelTree(T->lchild, ++deep); for (int x = 0; x < deep; x++) { printf("--"); } printf("%c\n", T->data); if (T->rchild != NULL) travelTree(T->rchild, deep); }
俺們也知道,遞歸算法的思想有其值的我們學習之處,但是,不過否認,遞歸的代價也是蠻高的,這得從遞歸的原理來分析,這里做一下簡單的敘述:
大家都知道遞歸的實現是通過調用函數本身,函數調用的時候,每次調用時要做地址保存,參數傳遞等,這是通過一個遞歸工作棧實現的。具體是每次調用函數本身要保存的內容包括:局部變量、形參、調用函數地址、返回值。那么,如果遞歸調用N次,就要分配N*局部變量、N*形參、N*調用函數地址、N*返回值。這勢必是影響效率的。
那么,作為遞歸的一種替代方式,棧的實現,就成為了一種不錯的選擇:下面我就簡單的敘述一下,如何在實現二叉樹的遍歷中來運用棧的思想:
其實嘛,說到底,遞歸的底層(系統級)實現也是使用棧的,如上所說,故遞歸的棧替換依舊不足為奇了,棧是一種先進后出結構的容器,通過簡單的數據結構(j結構體),我們即可以模擬棧的實現,當然,本文主要是談二叉樹的遍歷,至於棧的實現嗎,讀者自己去查嗎!!!
同樣,我們采用中序遍歷類舉例:
先敬上代碼:
voidt InOrderTraverse(BiTree T, int(*Visit)(TElemType e)){ InitStake(S); Push(S, T); while (!StackEmpty(S)) { while (GetTop(S,P)&&p) Push(S, p->lchild); Pop(S, p); //空指針null退棧 有左孩子時,在沿着左孩子方向遍歷的時候,會把一個 //null push進棧沒左孩子的時候,上一次循環就必定會push進一個null 兩種情況互斥 if (!StackEmpty(S)) { Pop(S, p); if (!Visit(p->data)) { return error; } Push(S, p->rchild); } } }
我們一一個簡單的二叉樹為例:
下面是棧操作過程:
其操作步驟可以簡介為如下:
1:沿着p左孩子方向深度遍歷值沒有左孩子的節並按循序入棧。(前提:有左孩子) 最對會帶一個空指針
去棧頂的空指針(此時棧頂絕對有一個空指針)
2:操作棧頂節點節點(訪問)
3:p指向此節點的右節點(不詢問) 即可能為空
重復。


