非遞迴中序遍歷二叉樹演算法詳解
注意學習這個演算法需要隨時可以在腦海中輸出二叉樹的中序遍歷的序列
舉例:
如上圖,我們就看到一棵二叉樹:那麼我們是不是馬上可以想到這棵二叉樹的中序遍歷序列是什麼呢?
我直接給出答案:D B EF A G H C I
我們如果不適用遞迴中序遍歷二叉樹即實現輸出二叉樹中的全部資料並且每個節點只訪問一次的操作。
那麼在我們的演算法中是通過單獨開記憶體來儲存節點資料,我們這個記憶體指的其實就是我們學過的棧資料結構Stack.
現在我們需要觀察中序序列的規律來把棧資料結構應用到這個演算法當中。
首先我們的中序遍歷是先遍歷A節點的左孩子節點在A節點在A的右孩子節點。 然後對應A的左孩子節點也就是B為根的一棵子樹, 我們還是先要訪問B節點的左子節點也就是D.
現在我們發現我們是訪問的B,然後是A,但是輸出結果確是DB, 那麼我們就發現一個規律就是先訪問的節點資料反而是後輸出,是不是和我們的棧資料結構的先進後出相似呢。 因此我們就聯絡到了stack資料結構,。
下面假如我們在訪問的過程就把節點入棧,直到左子節點為null,說明我們已經找到了可以輸出的資料起點,這個時候剛好我是把這個資料起點儲存在了棧資料結構最後一個,那麼這個時候我們入棧的次順依次是ABD。那麼我們出棧就等於是開始輸出中序遍歷的第一個資料,我們開始出棧D,由於是中序遍歷那麼我們接著出棧B,這個時候不能出棧了,因為我們需要輸出B節點的右子全部節點。因此我們又開始入棧F,然後是E.
然後我們在出棧棧首元素也就是E,我們用一個變數儲存下來,然後輸出E中的資料,接著出棧F,輸出其中的資料。 這個時候我們到了A這裡,我們在出棧A,在把右子樹入棧。在出棧。
大家發現了沒有,其實不用遞迴的話,我們中序遍歷輸出資料,用的是棧先入棧在出棧就得到資料。
現在我來貼上實現程式碼:
//上的程式碼類似虛擬碼
//非遞迴中序遍歷演算法 BT:儲存了二叉樹的地址 BT預設是根節點的地址
void InorderTraversal(BTree BT)
{
//開闢臨時變數儲存
BTree T =BT
//申明棧資料結構物件 Stack s = CreatStack(MaxSize); //初始化棧,預設大小為MaxSize //使用迴圈中序遍歷輸出節點資料 while(T) //什麼時候停止迴圈 假如T已經拿不到節點資料或者棧 { //用一個迴圈來壓棧 while(T) //我們需要T中儲存了節點的地址才可以壓棧 { s.Push(T); //把當前節點入棧 T->left; //轉向當前節點的左孩子節點 } //在用一個迴圈來出棧輸出資料 while(!s.Empty) { temp = s.Pop(); //出棧儲存當前棧頂節點 //準備輸出節點裡的資料內容 printf("%d",T->data); } //轉到右子樹壓棧 T = T->right; if(s.Empty) //當棧當中沒有元素說明已經輸出全部資料,那麼就要跳出迴圈 { break; } }
}