美文网首页
平衡二叉树的Python实现

平衡二叉树的Python实现

作者: 愤愤的有痣青年 | 来源:发表于2019-08-22 13:37 被阅读0次

    本文参考了这篇文章链接

    二叉平衡树是一种时间复杂度为O(log n)的二叉查找树,其定义如下:

    • 所有叶子节点的高度差最大为1
    • 左节点比右节点要小
    • 每个节点上最多只能有2个子节点(left, right)

    二叉平衡树的性质如下:

    • 每个节点都有一个平衡因子(bf), 其值为左节点的高度减去右节点的高度,该数有效范围为[-1,1]
    • 最小非平衡子树:在新节点插入前,距离被插入节点最近的一个平衡因子为1或者-1的节点为根节点组成的树.当插入新节点后导致树不平衡,可以调节此树至平衡,则整棵树就会平衡
    • 旋转:节点逆时针(左旋)或者顺时针(右旋)移动一个节点来调整树的高度

    以下为Python实现的代码,其中删除操作感觉这样方式不好,但我又找不到好的办法解决....

    class Node(object):
        def __init__(self, key, value, left=None, right=None):
            self.key = key  # 存储索引数值
            self.value = value  # 存储具体的数
            self.left = left  # 左节点
            self.right = right  # 右节点
            self.is_delete = False  # 删除标记, True为被删除,不会被搜索到
            self.bf = 0  # 平衡差,为左子树层级减去右子树层级,介于[-1,1]为合法值
    
    
    class BalancedBinaryTree(object):
        """
        最小不平衡树 距离插入节点处最近的一个bf为-1/1的节点,
        新插入的节点若插入后引起树的不平衡,只要更改此节点为平衡树,则整个树就会平衡
        """
    
        def __init__(self):
            self.root = None
    
        @staticmethod
        def left_whirl(node):
            """
            左旋
            当node值为-2的时候可以执行此操作使其节点值为0,node为最小不平衡树的根节点
            :param node:
            :return:
            """
            node.bf = node.right.bf = 0
    
            node_right = node.right
            node.right = node.right.left
            node_right.left = node
            return node_right
    
        @staticmethod
        def right_whirl(node):
            """
            右旋
            当node值为2的时候可以执行此操作使其节点值为0,node为最小不平衡树的根节点
            :param node:
            :return:
            """
            node.bf = node.left.bf = 0
    
            node_left = node.left
            node.left = node.left.right
            node_left.right = node
            return node_left
    
        @staticmethod
        def left_right_whirl(node):
            """
            左右旋,先左旋子节点,再右旋node节点
            :param node:
            :return:
            """
            node_b = node.left
            node_c = node_b.right
            node.left = node_c.right
            node_b.right = node_c.left
            node_c.left = node_b
    
            node_c.right = node
    
            if node_c.bf == 0:
                node.bf = node_b.bf = 0
            elif node_c.bf == 1:
                node.bf = -1
                node_b.bf = 0
            else:
                node.bf = 0
                node_b.bf = 1
    
            node_c.bf = 0
            return node_c
    
        @staticmethod
        def right_left_whirl(node):
            """
            右左旋,先右旋子节点,再左旋node节点
            :param node:
            :return:
            """
            node_b = node.right
            node_c = node_b.left
    
            node_b.left = node_c.right
            node.right = node_c.left
            node_c.right = node_b
    
            node_c.left = node
    
            if node_c.bf == 0:
                node.bf = node_b.bf = 0
            elif node_c.bf == 1:
                node.bf = 0
                node_b.bf = -1
            else:
                node.bf = 1
                node_b.bf = 0
    
            node_c.bf = 0
            return node_c
    
        def insert(self, key, value):
            """
            插入数据
            1 寻找插入点,并记录下距离该插入点的最小非平衡子树及其父子树
            2 修改最小非平衡子树到插入点的bf
            3 进行调整
            :param key:
            :param value:
            :return:
            """
    
            if not self.root:
                self.root = Node(key, value)
                return
    
            # a:最小非平衡树节点 p:插入点
            a, p = self.root, self.root
    
            # a与p节点的父节点,a_father用以链接旋转后的节点, p_father用以在循环时给a_father赋值
            a_father, p_father = None, None
    
            # 寻找插入点,并记录下距离该插入点的最小非平衡子树(a) 父子树(a_father) 插入点(p)
            while p:
                if p.key == key:
                    # 直接修改
                    p.value = value
                    return
    
                if p.bf != 0:
                    a_father, a = p_father, p
    
                p_father = p
                if key > p.key:
                    p = p.right
                else:
                    p = p.left
    
            # 插入点
            node = Node(key, value)
    
            if key > p_father.key:
                p_father.right = node
            else:
                p_father.left = node
    
            # 修改从a到插入点p的bf值
            ta = a
            while ta:
                if ta.key == key:
                    break
                elif key > ta.key:
                    ta.bf -= 1
                    ta = ta.right
                else:
                    ta.bf += 1
                    ta = ta.left
    
            # 判断新节点是插入在a子节点的左边(True)还是右边(False)
            if a.key > key:
                p_pos = a.left.key > key
            else:
                p_pos = a.right.key > key
    
            # 旋转修改
            if a.bf > 1:
                # 新节点插入到了a节点的左边并导致了不平衡,此时需要判断是要进行右旋转还是左右旋转
                if p_pos:
                    a = BalancedBinaryTree.right_whirl(a)
                else:
                    a = BalancedBinaryTree.left_right_whirl(a)
            elif a.bf < -1:
                # 新节点插入到了a节点的右边并导致了不平衡,此时需要判断是要进行左旋转还是右左旋转
                if p_pos:
                    a = BalancedBinaryTree.right_left_whirl(a)
                else:
                    a = BalancedBinaryTree.left_whirl(a)
    
            # 将调整后的a节点加入到a_father节点中
            if a_father:
                if a_father.key > key:
                    a_father.left = a
                else:
                    a_father.right = a
            else:
                self.root = a
    
        def delete(self, key):
            """
            删除节点并返回该节点的值
            :return:
            """
            p = self._search(key)
            if not p:
                return False
    
            p.is_delete = True
            return True
    
        def pop(self, key):
            p = self._search(key)
            if not p:
                return None
    
            p.is_delete = True
            return p.value
    
        def _search(self, key):
            p = self.root
            while p:
                if p.key == key:
                    if p.is_delete:
                        p = None
                    break
                elif p.key > key:
                    p = p.left
                else:
                    p = p.right
            else:
                return None
    
            return p
    
        def search(self, key):
            res = self._search(key)
            if res:
                return res.value
    
            return None
    
    
    if __name__ == "__main__":
        a = [(1, 'a'), (2, 'g'), (3, 'h'), (4, 'b'), (5, 'd'), (3.5, 'e')]
        bbt = BalancedBinaryTree()
        for item in a:
            bbt.insert(item[0], item[1])
        print(bbt.search(1), bbt.pop(1), bbt.search(1))
    
    

    相关文章

      网友评论

          本文标题:平衡二叉树的Python实现

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