myesn

myEsn2E9

hi
github

[二叉樹 binary tree]

[二叉樹 binary tree] 是一種非線性數據結構,代表著祖先與後代之間的派生關係,體現著” 一分為二 “的分治邏輯

二叉樹的基本單元是節點,每個節點有:** 值、[左子節點 left-child node]引用、[右子節點 right-child node]** 引用。

class TreeNode {
	int val;
  TreeNode? left;
	TreeNode? right;
	TreeNode(int x) => val = x;
}

在二叉樹中,除葉節點外,其他所有節點都包含子節點和非空子樹(子節點及其以下節點形成的樹)。
image

二叉樹的常見術語#

  • [根節點 root node]: 頂層節點,沒有父節點。
  • [葉節點 leaf node]: 沒有子節點的節點。
  • [邊 edge]: 連接兩個節點的線段,即節點引用(指針)。
  • 節點所在的 [層 level]: 從頂至底遞增,根節點所在層為 1。
  • 節點的 [度 degree]: 節點的子節點的數量。在二叉樹中,度的取值範圍是 0、1、2。
  • 二叉樹的 [高度 height]: 從根節點到最遠葉節點所經過的邊的數量。
  • 節點的 [深度 depth]: 從根節點到該節點所經過的邊的數量。
  • 節點的 [高度 height]: 從最遠葉節點到該節點所經過的邊的數量。
    image
    💡 請注意,通常將 “高度” 和 “深度” 定義為 “走過邊的數量”。

常見二叉樹類型#

1. [完美 (滿) 二叉樹 perfect binary tree]#

除了最底層外,其餘所有層的節點都被完全填滿。
image

2. [完全二叉樹 complete binary tree]#

只有最底層的節點未被填滿,且最底層節點盡量靠左填充。
image

3. [完滿二叉樹 full binary tree]#

除了葉節點之外,其餘所有節點都有兩個子節點。
image

4. [平衡二叉樹 balanced binary tree]#

任意節點的左子樹和右子樹的高度之差的絕對值不超過 1。
image

二叉樹遍歷#

[層序遍歷 level-order traversal]#

[層序遍歷 level-order traversal] 從頂部到底部逐層遍歷二叉樹,並在每一層按照從左到右的順序訪問節點。

層序遍歷本質上屬於 [廣度優先遍歷 breadth-first traversal],體現了” 一圈一圈向外擴展 “的逐層遍歷方式。

image

廣度優先遍歷通常借助” 隊列” 來實現

/* 層序遍歷 */
List<int> LevelOrder(TreeNode root) {
    // 初始化隊列,加入根節點
    Queue<TreeNode> queue = new();
    queue.Enqueue(root);
    // 初始化一個列表,用於保存遍歷序列
    List<int> list = new();
    while (queue.Count != 0) {
        TreeNode node = queue.Dequeue(); // 隊列出隊
        list.Add(node.val);              // 保存節點值
        if (node.left != null)
            queue.Enqueue(node.left);    // 左子節點入隊
        if (node.right != null)
            queue.Enqueue(node.right);   // 右子節點入隊
    }
    return list;
}

前序、中序、後序遍歷#

前序、中序、後序遍歷都屬於 [深度優先遍歷 depth-first traversal],它體現了一種”先走到頭,再回溯繼續“的遍歷方式。

深度優先遍歷就像是繞著整個二叉樹的外圍” 走 “一圈,在每個節點都會遇到三個位置,分別對應前序遍歷、中序遍歷和後序遍歷。
image

深度優先遍歷通常基於遞歸實現

/* **前序**遍歷 */
void PreOrder(TreeNode? root) {
    if (root == null) return;
    // 訪問優先級:**根**節點 -> **左**子樹 -> **右**子樹
    list.Add(root.val);
    PreOrder(root.left);
    PreOrder(root.right);
}

/* **中序**遍歷 */
void InOrder(TreeNode? root) {
    if (root == null) return;
    // 訪問優先級:**左**子樹 -> **根**節點 -> **右**子樹
    InOrder(root.left);
    list.Add(root.val);
    InOrder(root.right);
}

/* **後序**遍歷 */
void PostOrder(TreeNode? root) {
    if (root == null) return;
    // 訪問優先級:**左**子樹 -> **右**子樹 -> **根**節點
    PostOrder(root.left);
    PostOrder(root.right);
    list.Add(root.val);
}

記憶口訣:
前序:根左右,中序:左根右,後序:左右根。

參考#

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。