Binary Tree 二元樹
定義
binary tree 的每一個 node 最多只有兩個 subnode (子節點)
Complete Binary Tree(完全二元樹)
- 最後一層以外的層全部都是滿的
- 最後一層的節點全部向左靠
Binary Search Tree
\begin{align}
& \forall \text{ internal node } n \text{:} \\
& \text{1. } \forall l \in (n \text{‘s left subtree}), n \text{.key} > l \text{.key} \\
& \text{2. } \forall r \in (n \text{‘s right subtree}), n \text{.key} < r \text{.key} 
\end{align}
Template of Searching
curr = root
while ...condition_about_curr...:
  curr = curr.right if {curr.val is too small} else curr.left
return curr
相關例題
- Leetcode # 235. Lowest Common Ancestor of a Binary Search Tree
- Leetcode # 270. Closest Binary Search Tree Value
- Leetcode # 701. Insert into a Binary Search Tree
相關文章
Traversal 遍歷
總覽
| 方法 | Complexity | 
| 深度優先搜尋(Depth-First Search; use stack) 廣度優先搜尋(Breadth-First Search; use queue) | Time Complexity: O(N) Space Complexity: O(N) | 
| Recursive | Time Complexity: O(N) Space Complexity: O(N) | 
| Morris Traversal | Time Complexity: O(N) Space Complexity: O(1) | 
DFS
stack = [root]
while stack:
  cur = stack:pop()
  if cur is leaf:
    ...do some operation ...
  if cur.left:
    stack.attend(cur.left)
  if cur.right:
     stack.attend(cur.right)
BFS (Level Order Traversal)
queue = collections.deque(root)
while queue:
  cur = queue.popleft()
  if cur is leaf: 
    ...do some operation ... 
  if cur.left: 
    queue.attend(cur.left) 
  if cur.right: 
    queue.attend(cur.right)
前序/中序/後序 (Preorder / Inorder / Postorder) Traversal

- 前序:根節點 → 左子樹 → 右子樹
 (1 2 4 7 8 5 3 6 9 10)
- 中序:左子樹 → 根節點 → 右子樹
 (7 4 8 2 5 1 3 9 6 10)
- 後序:左子樹 → 右子樹 → 根節點
 (7 8 4 5 2 9 10 6 3 1)
Predecessor/Successor (上一個/下一個 node)
- Predecessor: 上一個 node
- Successor: 下一個 node
Pre-order/In-order/Post-order Traversal in Recursive
def traversal(root, order):
  if root is None:
    return []
  if order = "pre":
    return [cur] + traversal(cur.left) + traversal(cur.right)
  if order = "in":
    return traversal(cur.left) + [cur] + traversal(cur.right)
  if order = "post
    return traversal(cur.left) + traversal(cur.right) + [cur]
Expression Tree

- 前序 (Prefix) 或 波蘭表示法 (Polish notation)
 [× ÷ + 7 8 5 + 4 – 9 3]
- 中序 (Infix) :一般習慣的四則運算表示法
 [((7 + 8) ÷ 5) × (4 + 9 – 3)]
- 後序 (Postfix) 或 逆波蘭表示法 (Reverse Polish notation)
 [7 8 + 5 ÷ 4 9 3 – + ×]
Threaded Binary Tree
將未使用的 left/right subtree pointer
作為指向此 node 的 in-order predecessor/successor 的thread
Morris Traversal
和 Threaded Binary Tree 相同
使用未使用的 left/right subtree pointer
在移動前,先將現在位置 current
借用 predecessor.right 來記錄 (step 2.1)
這是我們第一次來到這個節點,之後向左移動
將來走到這個被修改過的 predecessor 後
利用現在的紀錄移動至 current 即當下的 seccessor 後 (step 1.)
再將該 predecessor.right 回復為空 (step 2.2)
這是我們再次回到這個節點,
並且已經遍歷完成左子樹,之後向左移動
Morris Traversal 的優點是
space complexity 為 O(1)
並且最終會將樹恢復為原狀
In-order Traversal
中序:左子樹 → 根節點 → 右子樹
輸出 current 的條件
- 沒有左子樹
- predecessor.right 不為空
 ⇒ 表示我們已遍歷完左子樹
流程
- 如果 current.left 為空,則輸出 current,
 且將 current 設為 current.right
- 如果 current.left 不為空,
 則找到 current 的 predecessor (左子樹的 most right node )- 如果 predecessor.right 為空,
 則將 predecessor.right 設為 current ,
 將 current 設為 current.left
- 如果 predecessor.right 不為空,
 則將 predecessor.right 設為空(將樹恢復原狀)。
 輸出 current ,將 current 設為 current.right
 
- 如果 predecessor.right 為空,
- 直到 current 為空停止

LeetCode # 94. Binary Tree Inorder Traversal
class Solution:
  def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
    if not root: return []
    return (self.inorderTraversal(root.left) if root.left else []) \
           + [root.val] \
           + (self.inorderTraversal(root.right) if root.right else [])
Pre-order Traversal
前序:根節點 → 左子樹 → 右子樹
輸出 current 的條件
- 沒有左子樹
- 去左子樹之前
 也就是我們尚未變更 predecessor.right
 predecessor.right 尚為空的時候
流程
- 如果 current.left 為空,則輸出 current,
 且將 current 設為 current.right
- 如果 current.left 不為空,
 則找到 current 的 predecessor (左子樹的 most right node )- 如果 predecessor.right 為空,輸出 current
 並將 predecessor.right 設為 current ,
 將 current 設為 current.left
- 如果 predecessor.right 不為空,
 則將 predecessor.right 設為空(將樹恢復原狀)。
 將 current 設為 current.right
 
- 如果 predecessor.right 為空,輸出 current
- 直到 current 為空停止

Post-order Traversal
後序:左子樹 → 右子樹 → 根節點
流程
前置作業:
令 dump = Node(0, root, 空)
current = dump
- 如果 current.left 為空,
 將 current 設為 current.right
- 如果 current.left 不為空,
 則找到 current 的 predecessor (左子樹的 most right node )- 如果 predecessor.right 為空
 並將 predecessor.right 設為 current ,
 將 current 設為 current.left
- 如果 predecessor.right 不為空,
 則將 predecessor.right 設為空(將樹恢復原狀)。
 從 predecessor 輸出至 current.left (from current.left to predecessor 的逆向輸出),
 將 current 設為 current.right
 
- 如果 predecessor.right 為空
- 直到 current 為空停止

逆向輸出
# Reverse the tree nodes 'from' -> 'to'.
# You should can arrive 'to' from 'from'
#   by each passed node's right subtree pointer.
def reverse(_from, to):
  if _from == to: return
  x, y = _from, _from.right
  while True:
    y, y.right, x = y.right, x, y
    if x == to: break
# Print the reversed tree nodes 'from' -> 'to'.
def print_reverse(_from, to):
  reverse(_from, to);
  p = to
  while True:
    print(p.val)
    if p == _from: break
    p = p->right
  reverse(to, _from)
相關例題
Others
Definition for a Binary Tree Node in LeetCode
Python
class TreeNode: 
  def __init__(self, val=0, left=None, right=None): 
    self.val = val 
    self.left = left 
    self.right = right
[Python] Binary Tree to List
def binary_tree_to_list(root, level=0):
  if root is None:
    return []
  btree_in_list = []
  curr_level = [root]
  has_next_level = True
  while has_next_level:
    has_next_level = False
    next_level = []
    val_this_level = []
    for node in curr_level:
      if node:
        has_next_level = True
        next_level += [node.left, node.right]
        val_this_level.append(node.val)
      else:
        next_level += [None] * 2
        val_this_level.append(None)
    btree_in_list += val_this_level if has_next_level else []
    curr_level = next_level
  for i in range(len(btree_in_list) - 1, -1, -1):
    if btree_in_list[i]:
      return btree_in_list[:i + 1]
Last Updated on 2024/04/27 by A1go
 
	
           
  