L14:数据结构-6(AVL树)

AVL树/平衡二叉树(AVL是三个人名的缩写)

  • AVL树是一棵自平衡的二叉搜索树
  • AVL树具有以下性质:
    • 根的左右子树的高度之差的绝对值不能查过1
    • 根的左右子树都是平衡二叉树
    • balance factor:左右子树的高度之差

AVL树的插入

  • 插入一个节点可能会破坏AVL树的平衡,可以通过旋转操作来进行修正
  • 插入一个节点后,只有从插入节点到根节点的路径上的节点的平衡可能被改变,需要找出第一个被破坏了平衡条件的节点,称之为K,K的两棵子树的高度差2
  • 不平衡的出现可能有4种情况:
    • 不平衡是由于对K的右孩子的右子树插入导致的:左旋
    • 不平衡是由于对K的左孩子的左子树插入导致的:右旋
    • 不平衡是由于对K的右孩子的左子树插入导致的:右旋-左旋
    • 不平衡是由于对K的左孩子的右子树插入导致的:左旋-右旋

 旋转实现

 代码:

from 数据结构-5(树和二叉树) import BiTreeNode, BST

class AVLNode(BiTreeNode):
    def __init__(self, data):
        BiTreeNode.__init__(self, data)
        self.bf = 0 #balance factor

class AVLTree(BST):
    def __init__(self, li=None):
        BST.__init__(self, li)

    def rotate_left(self, p, c): #左旋
        #p和c的位置关系看图
        #这个旋转函数在插入的时候用可以,删除的时候不行
        s2 = c.lchild
        p.rchild = s2
        if s2:
            s2.parent = p
        c.lchild = p
        p.parent = c
        #更新bf
        p.bf = 0
        c.bf = 0
        return c
   
    def rotate_right(self, p, c): #右旋
        #p和c的位置关系看图
        #这个旋转函数在插入的时候用可以,删除的时候不行
        s2 = c.rchild
        p.lchild = s2
        if s2:
            s2.parent = p
        c.rchild = p
        p.parent = c
        #更新bf
        p.bf = 0
        c.bf = 0
        return c

    def rotate_right_left(self, p, c): #右旋-左旋
        g = c.lchild
        s2 = g.lchild
        s3 = g.rchild

        c.lchild = s3
        if s3:
            s3.parent = c

        g.rchild = c
        c.parent = g

        p.rchild = s2
        if s2:
            s2.parent = p

        g.lchild = p
        p.parent = g

        #更新bf
        if g.bf > 0: #这里bf的计算方式是左减右,此时的情况是s2为h,s3为h-1
            p.bf = 0
            c.bf = -1
        elif g.bf < 0: #此时的情况是s3为h,s2为h-1
            p.bf = 1
            c.bf = 0
        else: #s1s2s3s4都为None,插入的是g
            p.bf = 0
            c.bf = 0
        g.bf = 0
        return g

    def rotate_left_right(self, p, c): #左旋-右旋
        g = c.rchild
        s2 = g.lchild
        s3 = g.rchild

        c.rchild = s2
        if s2:
            s2.parent = c

        g.lchild = c
        c.parent = g

        p.lchild = s3
        if s3:
            s3.parent = p

        g.rchild = p
        p.parent = g

        #更新bf
        if g.bf > 0: #这里bf的计算方式是左减右,此时的情况是s2为h,s3为h-1
            p.bf = -1
            c.bf = 0
        elif g.bf < 0: #此时的情况是s3为h,s2为h-1
            p.bf = 0
            c.bf = 1
        else: #s1s2s3s4都为None,插入的是g
            p.bf = 0
            c.bf = 0
        g.bf = 0
        return g

    def insert_no_rec(self, val):
        # 1. 和BST一样,插入
        p = self.root
        if not p: #空树
            self.root = BiTreeNode(val)
            return
        while True:
            if val < p.data:
                if p.lchild: #左孩子存在
                    p = p.lchild
                else:
                    p.lchild = BiTreeNode(val)
                    p.lchild.parent = p
                    node = p.lchild #node存储的是插入的节点
                    break
            elif val > p.data:
                if p.rchild:
                    p = p.rchild
                else:
                    p.rchild = BiTreeNode(val)
                    p.rchild.parent = p
                    node = p.rchild
                    break
            else:
                return

        # 2. 更新balance factor
        while node.parent: # node.parent不空 
        #这里的node是从下往上遍历的所有节点,不只是刚插入的那个节点了)
            if node.parent.lchild == node: #传递是从左子树来的,左子树更沉了
                #更新node.parent的bf += 1
                if node.parent.bf > 0: #原来node.parent.bf = 1,更新后变成2
                    #做旋转
                    #看node哪边沉
                    g = node.parent.parent #为了连接旋转之后的子树
                    x = node.parent #旋转前子树的根
                    if node.bf < 0: #右边沉
                        n = self.rotate_left_right(node.parent, node)
                    else:
                        n = self.rotate_right(node.parent, node)
                elif: node.parent.bf < 0: #原来node.parent.bf = -1,更新后变成0
                    node.parent.bf = 0
                    break
                else: #原来node.parent.bf = 0,更新后变成1
                    node.parent.bf = 1
                    node = node.parent
                    continue
            else: #传递是从右子树来的,右子树更沉了
                #更新node.parent的bf -= 1
                if node.parent.bf < 0: #原来node.parent.bf = -1,更新后变成-2
                    #做旋转
                    #看node哪边沉
                    g = node.parent.parent #为了连接旋转之后的子树
                    x = node.parent #旋转前子树的根
                    if node.bf > 0: #左边沉
                        n = self.rotate_right_left(node.parent, node)
                    else:
                        n = self.rotate_left(node.parent, node)
                elif: node.parent.bf > 0: #原来node.parent.bf = 1,更新后变成0
                    node.parent.bf = 0
                    break
                else: #原来node.parent.bf = 0,更新后变成-1
                    node.parent.bf = -1
                    node = node.parent
                    continue
            #连接旋转后的子树
            n.parent = g
            if g: # g不是空
                if x == g.lchild:
                    g.lchild = n
                else:
                    g.rchild = n
                break
            else: 
                self.root = n
                break       
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值