面試經典(13) 二叉樹非遞迴遍歷

2021-06-21 11:43:05 字數 1415 閱讀 2792

1.中序遍歷

中序遍歷的思路分析:第一次遍歷到節點,要一直遍歷到此節點左子樹上最左側的節點,此過程將遍歷到的節點按先後順序依次入棧。到大最左側時,將棧頂元素出棧並輸出,並將此節點的右子樹入棧,然後再從頭開始,是不是明顯看到遞迴的影子了!

**如下:

stacks;

void inorder(node *proot)

node *p=proot;

s.push(p);

while(!s.empty())

s.pop();

if(!s.empty())

}}

注意:上面**19行處if(!s.empty)這條判斷語句是不能省略的。因為當棧為空的時候,輸出節點會出錯。具體分析為什麼要加這個判定語句,從**看,while(不為空)進入迴圈,在進入if()判定之前有乙個pop動作,所以這有可能使棧為空,是什麼情況呢?就是在訪問中序遍歷的最後乙個節點時(」最右「節點)。中序遍歷訪問的最後乙個節點是「最右"節點(即它的右子樹肯定為空,如果它的右子樹非空,那麼遍歷會進入右子樹,那麼就不是最後訪問的節點)。這個」最右"元素node *p=top(),s.pop()出棧並輸出。然後s.push(p->m_right)(p->m_right為空),所以null入棧。接下來進入while迴圈,棧中只有乙個null,所以彈出null之後棧為空,如果不做判定直接輸出會報錯。分析這個過程的最簡單的例子是分析一棵只有乙個節點的樹(這個節點就是」最右"節點)來體會上述分析過程。

2.後續遍歷

後續遍歷的非遞迴方式是最複雜的。要保證根節點在左右子樹訪問之後訪問,對於任何乙個節點p,先將其入棧,如果p沒有左右子樹,直接出棧訪問,或者有左/右子樹,但是已經訪問過了,同樣可以出棧並訪問。如果不是這倆種情況,我們先將右子樹入棧,再將左子樹入棧,這樣保證了先訪問左子樹,在訪問右子樹,最後訪問根節點。

這裡的關鍵是怎麼確定當前節點cur的左右子樹是否應經訪問,可以使用pre指向當前節點cur前乙個訪問的節點,如果pre=cur->left(沒有右子樹)或者pre=cur->right(有右子樹),則表明cur的左右子樹已經訪問。

**:

void postorder(node *proot)

s.push(proot);

while(!s.empty())

else

}}

3.前序遍歷非遞迴

思路分析:

如果看懂了上面的後續遍歷,相信會很快寫出前序遍歷。前序遍歷會先遍歷根節點,然後遍歷左、右子樹。我們將棧頂元素出棧並輸出,如果根節點有左右子樹,然後將右子樹先入棧,再將左子樹入棧。

**如下:

void preorder(node *proot)

s.push(proot);

while(!s.empty())

}

參考:

二叉樹遍歷(遞迴 非遞迴)

二叉樹以及對二叉樹的三種遍歷 先根,中根,後根 的遞迴遍歷演算法實現,以及先根遍歷的非遞迴實現。node public class node public node left public node right public object value 遍歷訪問操作介面 public inte ce ...

二叉樹非遞迴遍歷

二叉樹非遞迴遍歷的幾個要點 1 不管前序 中序還是後序,它們的遍歷路線 或者說是回溯路線,先沿左邊一直走到盡頭,然後回溯到某節點,並跳轉到該節點的右孩子 如果有的話 然後又沿著這個有孩子的左邊一直走到盡頭 都是一樣的。2 明確每次回溯的目的。比如,前序回溯的目的是為了訪問右子樹 中序回溯的目的是為了...

非遞迴遍歷二叉樹

中序遞迴遍歷 void inordertrvdigui node pnode 然而,當樹的深度很大 比如16 時 假設為滿二叉樹 樹的節點數為 2 0 2 1 2 2 2 15 2 16 65536,遍歷整個二叉樹意味著有65536次函式呼叫,這將極大地增加程式執行時間。這時,應該採取非遞迴便利二叉...