美文网首页
二叉平衡树AVL笔记

二叉平衡树AVL笔记

作者: 江海小流 | 来源:发表于2019-08-23 15:08 被阅读0次

本文包括:

  1. 旋转示例图
  2. 基于balance factor来计算新的balance factor(比基于height)
  3. 实现代码

深色字体为 height
红色字体为 两个儿子节点的 height 之差
通过下面5个图,可以

  1. 很容易分情况把代码写出来
  2. 知道通过旋转后整个子树的高度变化(在插入删除的时候用于判断是否需要对父亲节点进行旋转操作)
2, 1 2, 0 2, -1, 0 2, -1, 1 2, -1, -1

剩下的5种情况,可以由上述5种情况通过镜面反转而获得。

旋转过程中 balance factor 的变化推导

右旋示例
  1. 如图所示,定义 h(\cdot) 为高度函数,如 h(A) = 3, h(B) = 2,定义 b(\cdot) 为获取AVL的节点的balance factor 函数,如b(A) = h(B) - h(C) = 1
  2. 定义旋转后的 A节点为 A', B节点为 B'
  3. 显然,b(A) = h(B) - h(C) = max(h(D), h(E))+1 - h(C)b(A') = h(E) - h(C) 成立。
  4. 那么,b(A) = max(h(D)-h(E), 0) + 1 + h(E) - h(C) = max(b(B), 0) + 1 + b(A')
  5. 因此可以通过 b(B)b(A) 求出b(A')b(A') = b(A) - max(b(B), 0) - 1
  6. 又因为 b(B') = h(D) - h(A') = h(D) - max(h(E), h(C)) - 1
  7. 那么,b(B') = h(D) - max(h(E), h(C)) + h(E) - h(E) +1 = h(D) - max(0, -b(A')) -1
  8. 因此,b(B') = h(D) + min(0, b(A')) - 1,通过第5步算出的 b(A')可以计算出 b(B')
  9. 至此,b(A')b(B') 均已通过 b(A)b(B) 计算得出。

同理左旋。

AVL python 实现

class TreeNode:
    
    def __init__(self, key, value, left_child=None, right_child=None, parent=None):
        self.key = key
        self.value = value
        self.parent = parent
        self.left_child = left_child
        self.right_child = right_child
        self.balance_factor = 0
    
    def has_left_child(self):
        return self.left_child is not None
    
    def has_right_child(self):
        return self.right_child is not None

    def is_right_child(self):
        return self.parent is not None and self.parent.right_child is self
    
    def is_left_child(self):
        return self.parent is not None and self.parent.left_child is self
    
    def is_root(self):
        return self.parent is None


class BinarySearchTree:
    
    def __init__(self):
        self.root = None
        
    def insert(self, key, value=None):
        if self.root is None:
            self.root = TreeNode(key, value)
        else:
            self._put(key, value, self.root)
    
    def contains(self, key):
        return self._get(key, self.root) is not None
    
    def delete(self, key):
        cur = self._get(key, self.root)
        
        if cur.has_left_child() and cur.has_right_child():
            new_cur = cur.left_child
            while new_cur.has_right_child():
                new_cur = new_cur.right_child
            cur.key, cur.value = new_cur.key, new_cur.value
            cur = new_cur
        
        if cur.is_root():
            self.root = cur.left_child if cur.has_left_child() else cur.right_child
            if self.root:
                self.root.parent = None
        else:
            if cur.is_left_child():
                cur.parent.left_child = cur.right_child if cur.has_right_child() else cur.left_child
                if cur.parent.left_child:
                    cur.parent.left_child.parent = cur.parent
                cur.parent.balance_factor -= 1
            else:
                cur.parent.right_child = cur.right_child if cur.has_right_child() else cur.left_child
                if cur.parent.right_child:
                    cur.parent.right_child.parent = cur.parent
                cur.parent.balance_factor += 1
            self._update_balance(cur.parent, -1)
        
    def _get(self, key, current_node):
        if current_node is None:
            return None
        if key == current_node.key:
            return current_node
        return self._get(key, current_node.left_child) if key < current_node.key else self._get(key, current_node.right_child)
    
    def _put(self,key,value,current_node):
        if key < current_node.key:
            if current_node.has_left_child():
                self._put(key,value,current_node.left_child)
            else:
                current_node.left_child = TreeNode(key,value,parent=current_node)
                self._update_balance(current_node.left_child)
        else:
            if current_node.has_right_child():
                self._put(key,value,current_node.right_child)
            else:
                current_node.right_child = TreeNode(key,value,parent=current_node)
                self._update_balance(current_node.right_child)

    def _update_balance(self, node, inc=1):
        if node.balance_factor > 1 or node.balance_factor < -1:
            self._rebalance(node)
            return
        if not node.is_root():
            if node.is_left_child():
                node.parent.balance_factor += inc
            elif node.is_right_child():
                node.parent.balance_factor -= inc

            if node.parent.balance_factor != 0:
                self._update_balance(node.parent)
    
    def _rotate_left(self,rot_root):
        new_root = rot_root.right_child
        rot_root.right_child = new_root.left_child
        if new_root.has_left_child():
            new_root.left_child.parent = rot_root
        new_root.parent = rot_root.parent
        if rot_root.is_root():
            self.root = new_root
        else:
            if rot_root.is_left_child():
                rot_root.parent.left_child = new_root
            else:
                rot_root.parent.right_child = new_root
        new_root.left_child = rot_root
        rot_root.parent = new_root
        rot_root.balance_factor = rot_root.balance_factor + 1 - min(new_root.balance_factor, 0)
        new_root.balance_factor = new_root.balance_factor + 1 + max(rot_root.balance_factor, 0)
    
    def _rotate_right(self, rot_root):
        new_root = rot_root.left_child
        rot_root.left_child = new_root.right_child
        if new_root.has_right_child():
            new_root.right_child.parent = rot_root
        new_root.parent = rot_root.parent
        if rot_root.is_root():
            self.root = new_root
        else:
            if rot_root.is_left_child():
                rot_root.parent.left_child = new_root
            else:
                rot_root.parent.right_child = new_root
        new_root.right_child = rot_root
        rot_root.parent = new_root
        rot_root.balance_factor = rot_root.balance_factor - 1 - max(new_root.balance_factor, 0)
        new_root.balance_factor = new_root.balance_factor - 1 + min(rot_root.balance_factor, 0)
        
    def _rebalance(self,node):
        if node.balance_factor < 0:
            if node.right_child.balance_factor > 0:
                self._rotate_right(node.right_child)
                self._rotate_left(node)
            else:
                self._rotate_left(node)
        elif node.balance_factor > 0:
            if node.left_child.balance_factor < 0:
                self._rotate_left(node.left_child)
                self._rotate_right(node)
            else:
                self._rotate_right(node)

相关文章

网友评论

      本文标题:二叉平衡树AVL笔记

      本文链接:https://www.haomeiwen.com/subject/kyhtectx.html