1. 程式人生 > >二叉樹前序遍歷、中序遍歷、後序遍歷、層序遍歷的直觀理解

二叉樹前序遍歷、中序遍歷、後序遍歷、層序遍歷的直觀理解

0. 寫在最前面

    複習到二叉樹,看到網上諸多部落格文章各種繞,記得頭暈。個人覺得數學、演算法這些東西都是可以更直觀簡潔地表示,然後被記住的,並不需要靠死記硬背。

本文的程式基本來源於《大話資料結構》,個人感覺是一本非常好的書,推薦去看。

1. 為什麼叫前序、後序、中序?

    一棵二叉樹由根結點、左子樹和右子樹三部分組成,若規定 D、L、R 分別代表遍歷根結點、遍歷左子樹、遍歷右子樹,則二叉樹的遍歷方式有 6 種:DLR、DRL、LDR、LRD、RDL、RLD。由於先遍歷左子樹和先遍歷右子樹在演算法設計上沒有本質區別,所以,只討論三種方式:

DLR--前序遍歷(根在前,從左往右,一棵樹的根永遠在左子樹前面,左子樹又永遠在右子樹前面 )

LDR--中序遍歷(根在中,從左往右,一棵樹的左子樹永遠在根前面,根永遠在右子樹前面)

LRD--後序遍歷(根在後,從左往右,一棵樹的左子樹永遠在右子樹前面,右子樹永遠在根前面)

需要注意幾點:

  1. 根是相對的,對於整棵樹而言只有一個根,但對於每棵子樹而言,又有自己的根。比如對於下面三個圖,對於整棵樹而言,A是根,A分別在最前面、中間、後面被遍歷到。而對於D,它是G和H的根,對於D、G、H這棵小樹而言,順序分別是DGH、GDH、GHD;對於C,它是E和F的根,三種排序的順序分別為: CEF、ECF、EFC。是不是根上面的DLR、LDR、LRD一模一樣呢~~
  2. 整棵樹的起點,就如上面所說的,從A開始,前序遍歷的話,一棵樹的根永遠在左子樹前面,左子樹又永遠在右子樹前面,你就找他的起點好了。
  3. 二叉樹結點的先根序列、中根序列和後根序列中,所有葉子結點的先後順序一樣
  4. 建議看看文末第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.《大話資料結構》