11.python实现AVL平衡二叉树

排序二叉树中存在一个问题就是可能会退化成一个链表,当只有左子树或者右子树有节点的时候,此时排序二叉树就像链表一样,但因为排序二叉树在插入查询的时候还要判断左右子树的问题,这样查询的效率反而变低,从而引出了平衡二叉树

平衡二叉树又称平衡搜索树(Self-balance Binary Search Tree)又称AVL树,同时保证了查询和添加的效率。首先平衡二叉树是一颗排序二叉树,且它是空树或者他的每一个节点分支的左右两颗子树的高度差值的绝对值小于等于1。平衡二叉树的实现方法主要有红黑树,AVL,替罪羊树,Treap,伸展树等

class Node(object):
    def __init__(self, data):
        self.data = data
        self.parent = None
        self.left = None
        self.right = None

    def __str__(self):
        return str(self.data)

    def add(self, node):
        if self.data > node.data:
            if self.left is None:
                self.left = node
                node.parent = self
            else:
                self.left.add(node)
        else:
            if self.right is None:
                self.right = node
                node.parent = self
            else:
                self.right.add(node)
        if self.left_height() - self.right_height() > 1:
            # 左高右低 右旋转
            if self.left is not None and self.left.right_height() > self.left.left_height():
                # 如果目标节点的左子树的右子树的高度大于目标节点的右子树高度 需要先进行左旋转
                self.left_rotate()
            self.right_rotate()
        if self.right_height() - self.left_height() > 1:
            # 右高左低 左旋转self.left.left
            if self.right is not None and self.right.left_height() > self.right.right_height():
                self.right_rotate()
            self.left_rotate()

    def height(self):
        """
        获取树的高度
        :return:
        """
        return max(self.left.height() if self.left is not None else 0,
                   self.right.height() if self.right is not None else 0) + 1

    def left_height(self):
        return 0 if self.left is None else self.left.height()

    def right_height(self):
        return 0 if self.right is None else self.right.height()

    def pre_order(self):
        """
        前序遍历
        :return:
        """
        print(self, end='->')
        if self.left is not None:
            self.left.pre_order()
        if self.right is not None:
            self.right.pre_order()

    def in_order(self):
        """
        中序遍历
        :return:
        """
        if self.left is not None:
            self.left.in_order()
        print(self, end='->')
        if self.right is not None:
            self.right.in_order()

    def post_order(self):
        """
        后续遍历
        :return:
        """
        if self.left is not None:
            self.left.post_order()
        if self.right is not None:
            self.right.post_order()
        print(self, end='->')

    def find(self, data):
        """
        查找
        :param data:
        :return:
        """
        if self.data == data:
            return self
        elif data > self.data:
            # 右找
            return self.right.find(data)
        else:
            return self.left.find(data)

    def find_min(self):
        """
        找到一某一个节点为根节点的左小值
        :return:
        """
        if self.left is not None:
            temp = self
            while temp.left is not None:
                temp = temp.left
            return temp
        return self

    def is_leaf(self):
        """
         判断当前节点是否是叶子节点
        :return:
        """
        return self.left is None and self.right is None

    def delete(self, data):
        """
        - 先找到待删除节点,因为现在树是单向的需要把待删除节点的父节点也找到
        - 如果待删除节点是一个叶子节点,判断待删除节点是父节点的左节点还是右节点,找到之后相应指针置空即可
        - 如果待删除节点是一个非叶子节点,且只有一颗子树的情况
          - 首先确定待删除节点的子树是左子树还是右子树,为了下一步挂到父节点上
          - 再确定待删除节点是父节点的左节点还是右节点,把之前确定的子树挂在对应的节点上l
          - 因为根节点没有父节点需要做特殊处理
        - 如果待删除节点是一个非叶子节点,且有两颗子树的情况
          - 从待删除节点的右子树中找到最小的一个节点,或者从待删除节点左子树找到最大的一个节点
          - 删除在子树中找到的这个节点
          - 将待删除节点的值替换成刚才删除的节点的值即可形成新的顺序二叉树
        :return:
        """
        # 先找到待删除节点,因为现在树是单向的需要把待删除节点的父节点也找到
        target_node = self.find(data)
        if target_node is None:
            return
        else:
            # 如果待删除节点是一个叶子节点,判断待删除节点是父节点的左节点还是右节点,找到之后相应指针置空即可
            parent = target_node.parent
            if target_node.is_leaf():
                if parent.left is target_node:
                    target_node.parent.left = None
                if parent.right is target_node:
                    target_node.parent.right = None
            else:
                # 存在子树的情况
                if target_node.left is not None and target_node.right is not None:
                    # 如果待删除节点是一个非叶子节点,且有两颗子树的情况
                    # 从待删除节点的右子树中找到最小的一个节点,或者从待删除节点左子树找到最大的一个节点
                    min_node = target_node.right.find_min()
                    # 删除在子树中找到的这个节点
                    self.delete(min_node.data)
                    # 将待删除节点的值替换成刚才删除的节点的值即可形成新的顺序二叉树
                    target_node.data = min_node.data
                else:
                    # 如果待删除节点是一个非叶子节点,且只有一颗子树的情况
                    if parent is not None:
                        # 首先确定待删除节点的子树是左子树还是右子树,为了下一步挂到父节点上
                        # 再确定待删除节点是父节点的左节点还是右节点,把之前确定的子树挂在对应的节点上
                        if parent.left is target_node and target_node.left is not None:
                            parent.left = target_node.left
                        elif parent.right is target_node and target_node.left is not None:
                            parent.right = target_node.left
                        elif parent.left is target_node and target_node.right is not None:
                            parent.left = target_node.right
                        elif parent.right is target_node and target_node.right is not None:
                            parent.right = target_node.right
                    else:
                        # 因为根节点没有父节点需要做特殊处理
                        pass

    def right_rotate(self):
        """
        右旋转
        :return:
        """
        temp = Node(self.data)
        temp.right = self.right
        self.data = self.left.data
        self.left = self.left.left
        self.right = temp

    def left_rotate(self):
        """
        左旋转
        :return:
        """
        temp = Node(self.data)
        temp.left = self.left
        self.data = self.right.data
        self.right = self.right.right
        self.left = temp


class BinaryTree(object):
    def __init__(self):
        self.root = None

    def add(self, node):
        if self.root is None:
            self.root = node
        else:
            self.root.add(node)

    def pre_order(self):
        if self.root is not None:
            self.root.pre_order()
            print()

    def in_order(self):
        if self.root is not None:
            self.root.in_order()
            print()
        else:
            raise Exception('tree is empty!')

    def post_order(self):
        if self.root is not None:
            self.root.post_order()
            print()

    def find(self, data):
        if self.root is None:
            return
        else:
            self.root.find(data)

    def delete(self, data):
        if self.root is None:
            return
        elif self.root.data == data and self.root.left is None and self.root.right is None:
            self.root = None
            return
        else:
            self.root.delete(data)

    def height(self):
        return 0 if self.root is None else self.root.height()


if __name__ == '__main__':
    binary_tree = BinaryTree()
    # for i in range(1, 6):
    #     binary_tree.add(Node(random.randint(0, 25)))
    # binary_tree.pre_order()
    # print()
    # binary_tree.in_order()
    # print()
    # binary_tree.post_order()
    # 测试删除
    # arr = [7, 3, 10, 12, 5, 1, 9, 2]
    # for i in arr:
    #     binary_tree.add(Node(i))
    # binary_tree.in_order()
    # # binary_tree.delete(5)
    # # binary_tree.in_order()
    # binary_tree.delete(10)
    # binary_tree.in_order()
    # binary_tree.delete(2)
    # binary_tree.in_order()
    # binary_tree.delete(3)
    # binary_tree.in_order()
    # binary_tree.delete(1)
    # binary_tree.in_order()
    # binary_tree.delete(7)
    # binary_tree.in_order()
    # binary_tree.delete(9)
    # binary_tree.in_order()
    # binary_tree.delete(5)
    # binary_tree.in_order()
    # binary_tree.delete(12)
    # binary_tree.in_order()
    # 测试旋转
    binary_tree.add(Node(7))
    binary_tree.add(Node(5))
    binary_tree.add(Node(4))
    print(binary_tree.height())
    binary_tree.add(Node(3))
    binary_tree.add(Node(8))
    binary_tree.pre_order()
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值