二叉樹前序遍歷、中序遍歷、後序遍歷、層序遍歷的直觀理解
阿新 • • 發佈:2019-02-11
0. 寫在最前面
複習到二叉樹,看到網上諸多部落格文章各種繞,記得頭暈。個人覺得數學、演算法這些東西都是可以更直觀簡潔地表示,然後被記住的,並不需要靠死記硬背。
本文的程式基本來源於《大話資料結構》,個人感覺是一本非常好的書,推薦去看。
1. 為什麼叫前序、後序、中序?
一棵二叉樹由根結點、左子樹和右子樹三部分組成,若規定 D、L、R 分別代表遍歷根結點、遍歷左子樹、遍歷右子樹,則二叉樹的遍歷方式有 6 種:DLR、DRL、LDR、LRD、RDL、RLD。由於先遍歷左子樹和先遍歷右子樹在演算法設計上沒有本質區別,所以,只討論三種方式:
DLR--前序遍歷(根在前,從左往右,一棵樹的根永遠在左子樹前面,左子樹又永遠在右子樹前面 )
LDR--中序遍歷(根在中,從左往右,一棵樹的左子樹永遠在根前面,根永遠在右子樹前面)
LRD--後序遍歷(根在後,從左往右,一棵樹的左子樹永遠在右子樹前面,右子樹永遠在根前面)
需要注意幾點:
- 根是相對的,對於整棵樹而言只有一個根,但對於每棵子樹而言,又有自己的根。比如對於下面三個圖,對於整棵樹而言,A是根,A分別在最前面、中間、後面被遍歷到。而對於D,它是G和H的根,對於D、G、H這棵小樹而言,順序分別是DGH、GDH、GHD;對於C,它是E和F的根,三種排序的順序分別為: CEF、ECF、EFC。是不是根上面的DLR、LDR、LRD一模一樣呢~~
- 整棵樹的起點,就如上面所說的,從A開始,前序遍歷的話,一棵樹的根永遠在左子樹前面,左子樹又永遠在右子樹前面,你就找他的起點好了。
- 二叉樹結點的先根序列、中根序列和後根序列中,所有葉子結點的先後順序一樣
- 建議看看文末第3個參考有趣詳細的推導
前序遍歷(DLR) 中序遍歷(LDR) 後序遍歷(LRD)
2. 演算法上的前中後序實現
除了下面的遞迴實現,還有一種使用棧的非遞迴實現。因為遞迴實現比較簡單,且容易關聯到前中後,所以
typedef struct TreeNode { int data; TreeNode * left; TreeNode * right; TreeNode * parent; }TreeNode; void pre_order(TreeNode * Node)//前序遍歷遞迴演算法 { if(Node == NULL) return; printf("%d ", Node->data);//顯示節點資料,可以更改為其他操作。在前面 pre_order(Node->left); pre_order(Node->right); } void middle_order(TreeNode *Node)//中序遍歷遞迴演算法 { if(Node == NULL) return; middle_order(Node->left); printf("%d ", Node->data);//在中間 middle_order(Node->right); } void post_order(TreeNode *Node)//後序遍歷遞迴演算法 { if(Node == NULL) return; post_order(Node->left); post_order(Node->right); printf("%d ", Node->data);//在最後 }
3. 層序遍歷
層序遍歷嘛,就是按層,從上到下,從左到右遍歷,這個沒啥好說的。
參考
1.《大話資料結構》