1. 程式人生 > >二叉搜尋樹(binary search tree)

二叉搜尋樹(binary search tree)

BST1

性質

設 x 是二叉搜尋樹中的一個結點。如果 y 是 x 左子樹中的一個結點,那麼 y.key ≤ x.key。如果 y 是 x 右子樹中的一個結點,那麼 y.key ≥ x.key。

特性

期望高度:height = O(lgn)

基本操作平均時間複雜度:Operations = Θ(lgn)

操作

遍歷:時間複雜度 θ(n),n 為總結點數。

INORDER_TREE_WALK
    if x != NIL
        INORDER_TREE_WALK(x.left)
        print x.key
        INORDER_TREE_WALK(x
.right)

搜尋指定鍵值:中序遍歷查詢指定鍵值。時間複雜度 O(height)。

TREE_SEARCH(x, k)
    if x == NIL or k == x.key
        return x
    if k < x.key
        return TREE_SEARCH(x.left, k)
    else
        return TREE_SEARCH(x.right, k)
ITERATIVE_TREE_SEARCH(x, k)
    while x != NIL and k != x.key
        if k < x.key
x = x.left else x = x.right return x

查詢最小值:遞迴查詢最左結點。時間複雜度 O(height)。

TREE_MINIMUM(x)
    while x.left != NIL
        x = x.left
    return x

查詢最大值:遞迴查詢最右結點。時間複雜度 O(height)。

TREE_MAXIMUM(x)
    while x.right != NIL
        x = x.right
    return x

後繼:時間複雜度 O(height)。

實現分為兩種情況:
* 結點 x 的右子樹非空,則右子樹的最左結點就是 x 的後繼。
* 結點 x 的右子樹為空,則後繼 y 滿足: y 的左子樹存在且同時是 x 的祖先, y 是符合前面性質的最底層的 x 的祖先。

TREE_SUCCESSOR(x)
    if x.right != NIL
        return TREE_MINIMUM(x.right)
    y = x.p
    while y != NIL and x == y.right
        x = y
        y = y.p
    return y

前驅:時間複雜度 O(height)。

實現分為兩種情況:
* 結點 x 的左子樹非空,則左子樹的最右結點就是 x 的前驅。
* 結點 x 的左子樹為空,則前驅 y 滿足:y 的右子樹存在且同時是 x 的祖先,y 是符合前面性質的最底層的 x 的祖先。

TREE_PREDECESSOR(x)
    if x.left != NIL
        return TREE_MAXIMUM(x.left)
    y = x.p
    while y != NIL and x == y.left
        x = y
        y = y.p
    return y

插入:時間複雜度 O(height)。

實現:
1. 查詢新結點放置的位置。
* 從樹的根節點開始,新結點和當前結點的值比較,根據情況向左或右遍歷。
* 迴圈a,直到得出的當前節點為NILL為止,這個當前結點的位置就是新結點要插入的位置。
2. 放置新結點。根據新結點與前面得到的結點的父結點比較,確定位置並插入。

TREE_INSERT(T, z)
    y = NIL
    x = T.root
    while x != NIL
        y = x
        if z.key < x.key
            x = x.left
        else
            x = x.right
    z.p = y
    if y == NIL
        T.root = z // tree T was empty
    elseif z.key < y.key
        y.left = z
    else
        y.right = z

刪除:時間複雜度 O(height)

實現策略分為三種情況,設要刪除的結點為 z :
* 如果 z 沒有孩子結點,那麼簡單地將它刪除,並修改它的父結點,用NIL作為孩子來替換 z 。
* 如果 z 有一個孩子,那麼將這個孩子提升到樹中 z 的位置上,並修改 z 的父結點,用 z 的孩子來替換 z 。
* 如果 z 有兩個孩子, 那麼找 z 的後繼 y (一定在 z 的右子樹上),並讓 y 佔據樹中 z 的位置。z 的原右子樹部分稱為y的新的右子樹,並且 z 的左子樹成為 y 的新的左子樹。

TRANSPLANT(T, u, v)
    if u.p == NIL
        T.root = u
    elseif u == u.p.left
        u.p.left = v
    else
        u.p.right = v
    if v != NIL
        v.p = u.p

TREE_DELETE(T, z)
    if z.left == NIL
        TRANSPLANT(T, z, z.right)
    elseif z.right == NIL
        TRANSPLANT(T, z, z.left)
    else 
        y = TREE_MINIMUM(z.right)
        if y.p != z
            TRANSPLANT(T, y, y.right)
            y.right = z.right
            y.right.p = y
        TRANSPLANT(T, z, y)
        y.left = z.left
        y.left.p = y