MIT6.006 lecture007

107 阅读1分钟

Height Balance:

  • maintain the height of the tree is O(logn)O(logn)
  • AVL Tree

Rotations:

Change the subtree's height without changing the traversal order .

Snipaste_2024-04-11_16-18-47.png

def subtree_rotate_right(D):
    assert D.left
    B, E = D.left, D.right
    A, C = B.left, B.right
    D, B = B, D
    D.item, B.item = B.item, D.item
    B.left, B.right = A, D
    D.left, D.right = C, E
    if A: A.parent = B
    if E: E.parent = D

AVL Trees: hight balance

AVL trees maintain the height-balance,which calls the AVL Property.

  • left and right subtree's height differ by most 1

Df:

F(h)=F(h1)+F(h2)+1>F(h1)+F(h2)>F(h2)2=2h/2F(h)=F(h-1)+F(h-2)+1>F(h-1)+F(h-2)> F(h-2) \cdot 2=2^{h/2}


F(h)=2Ω(h)F(h)=2^{\Omega(h)}

def subtree_rotate_right(D):
    assert D.left
    B, E = D.left, D.right
    A, C = B.left, B.right
    D, B = B, D
    D.item, B.item = B.item, D.item
    B.left, B.right = A, D
    D.left, D.right = C, E
    if A: A.parent = B
    if E: E.parent = D
def skew(A):
    return height(A.right) - height(A.left)


def rebalance(A):
    if skew(A) == 2:
        if A.right.skew() < 0:
            A.right.subtree_rotate_right()
        A.subtree_rotate_left()
    elif skew(A) == -2:
        if A.left.skew() > 0:
            A.left.subtree_rotate_left()
        A.subtree_rotate_right()


def maintain(A):
    A.rebalance
    if A.parent:
        A.parent.maintain()

Height:

If we want to compute the skew of the tree,the heght of the subtree is essential.

And if we want to rebalance the tree in O(logn)O(logn) time,we need to compute each node's height in O(1)timeO(1) time . Instead of computing each node's height every time we need ,we speed up the computation via augmentation.

def height(A):
    if A is None: return -1
    return 1 + max(height(A.left), height(A.right))


# Why if A is None,we will return -1
# When A is a leaf node(A doesn't have the subtree), we will return " 1+ -1 == 0 "
# the zero results that,we won't plus 1 to the hieght.
# Samely the root node's height is 0.

def height(A):
    if A:
        return height(A)
    else:
        return -1


def subtree_update(A):
    A.height = 1 + max(height(A.left), height(A.right))
    

Full inplementation with AVL balancing:

def height(A):
    if A:
        return A.height
    else:
        return -1


class Binary_Node():
    def __init__(self, A, x):
        A.item = x
        A.left = None
        A.right = None
        A.parent = None
        A.subtree_update()

    def subtree_update(self, A):
        A.height = 1 + max(height(A.left), height(A.right))

    def skew(self, A):
        return height(A.right) - height(A.left)

    def subtree_iter(selfA):
        if A.left: yield from A.left.subtree_iter()
        yield A
        if A.right: yield from A.right.subtree_iter()


def subtree_first(A):
    if A.left:
        return A.left.subtree_first()
    else:
        return A


def subtree_last(A):
    if A.right:
        return A.right.subtree_last()
    else:
        return A


def successor(A):
    if A.right:
        return A.right.subtree_first
    while A.parent and (A is A.parent.right):
        A = A.parent
    return A.parent


def predecessor(A):
    if A.left:
        return A.left.subtree_last()
    while A.parent and (A is A.parent.left):
        A = A.parent
    return A.parent


def subtree_insert_before(A, B):
    if A.left:
        A = A.left.subtree_last()
        A.right, B.parent = B, A
    else:
        A.left, B.parent = B, A
    A.maintain()


def subtree_insert_after(A, B):
    if A.right:
        A = A.right.subtree_first()
        A.left, B.parent = B, A
    else:
        A.right, B.parent = B, A
    A.maintain()


def subtree_delete(A):
    if A.left or A.right:
        if A.left:
            B = A.predecessor()
        else:
            B = A.successor()
        A.item, B = item = B.item, A.item
        return B.subtree_delete()
    if A.parent:
        if A.parent.left is A:
            A.parent.left is None
        else:
            A.parent.right is None
        A.parent.maintain()
    return A.parent


def subtree_rotate_right(D):
    assert D.left
    B, E = D.left, D.right
    A, C = B.left, B.right
    B, D = D, B
    D.item, B.item = B.item, D.item
    B.left, B.right = A, D
    D.left, D.right = C, E
    if A: A.parent = B
    if E: E.parent = D
    B.subtree_maintain()
    D.subtree_maintain()


def rebalance(A):
    if A.skew() == 2:
        if A.right.skew() < 0:
            A.left.subtree_rotate_right()
        A.subtree_rotate_left()
    elif A.skew == -2:
        if A.left.skew() > 0:
            A.left.subtree_rotate_left()
        A.subtree_rotate_right()


def maintain(A):
    A.rebalance()
    A.subtree_update()
    if A.parent():
        A.parent.maintain()
       

Sequence Application:

class Size_Node(Binary_Node):
    def subtree_update(self, A):
        super().subtree_update()
        A.size = 1
        if A.left: A.size += A.left.size
        if A.right: A.size += A.right.size

    def subtree_at(self, A, i):
        assert i >= 0
        if A.left:
            L_size = A.left.size
        else:
            L_size = 0
        if i < L_size:
            return A.left.subtree_at(i)
        elif i > L_size:
            return A.right.subtree_at(i - L_i - 1)
        else:
            return A