数据结构--AVL树

引用链接

二叉搜索树的效率

平均情况下,二叉搜索树进行搜索的时间复杂度为O(lgn)
最坏情况下,二叉搜索树可能非常偏斜。
解决方案:随机化插入、AVL树

AVL树

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

AVL树–插入

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

from BinaryTree_delete import BiTreeNode,BST
class AVLNode(BiTreeNode):
    def __init__(self,data):
        BiTreeNode.__init__(self,data)
        self.bf=0
class AVLTree(BST):
    def __init__(self,li=None):
        BST.__init__(self,li)
    def rotate_left(self,p,c):
        s2=c.lchild
        p.rchild=s2
        if s2:
            s2.parent=p
        c.lchild=p
        p.parent=c
        p.bf=0
        c.bf=0
        return c
    def rotate_right(self,p,c):
        s2=c.rchild
        p.lchild=s2
        if s2:
            s2.parent=p
        c.rchild=p
        p.parent=c
        p.bf=0
        c.bf=0
        return c
    def rotate_right_left(self,p,c):
        g=c.lchild
        s3=g.rchild
        c.lchild=s3
        if s3:
            s3.parent=c
        g.rchild=c
        c.parent=g
        s2=g.lchild
        p.rchild=s2
        if s2:
            s2.parent=p
        g.lchild=p
        p.parent=g
        #更新bf
        if g.bf>0:  #右偏,插入到s3上
           p.bf=-1
           c.bf=0
        elif g.bf<0:   #左偏,插入到s2上
            p.bf=0
            c.bf=1
        else: #插入的是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
        c.rchild=s2
        if s2:
            s2.parent=c
        g.lchild=c
        c.parent=g
        s3=g.rchild
        p.lchild=s3
        if s3:
            s3.parent=p
        g.rchild=p
        p.parent=g
        #更新bf
        if g.bf<0:
           p.bf=1
           c.bf=0
        if g.bf>0:
            p.bf=0
            c.bf=-1
        else:
            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:  #val==p.data
                return
        #2.更新balance factor
        while node.parent: #node.parent不变
            if node.parent.lchild==node: #传递是从左子树来的,左子树更沉了
                #更新node.parent的bf -=1
                if node.parent.bf<0: #原来node.parent.bf=-1,更新后为-2,需要做旋转
                    #如果node.parent.bf<0,有两种情况,右旋,左旋右旋,所以要看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)
                    #记得:把n和g连起来
                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: #node.bf=-1,左边沉
                        n=self.rotate_right_left(node.parent,node)
                    else:         #node.bf=1,右边沉
                        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


tree=AVLTree([9,8,7,6,5,4,3,2,1])
tree.pre_order(tree.root)
print("\n")
tree.in_order(tree.root)

二叉搜索树扩展应用–B树

B树(B-Tree):B树是一颗自平衡的多路搜索树。常用于数据库的索引。

你可能感兴趣的:(数据结构)