AVL树是一棵自平衡的二叉搜索树。node
balance factor(平衡因子)记录了左右子树的高度差。上图定义的是有左子树没有右子树差值是1,没有左子树有右子树差值是-1.python
插入一个节点可能会破坏AVL树的平衡,能够经过旋转操做来进行修正。spa
插入一个节点后,只有从插入节点到根节点的路径上的节点的平衡可能被改变。blog
咱们须要找出第一个破坏了平衡条件的节点,称之为K。K的两颗子树的高度差为2。it
(1)不平衡是因为对K的右孩子的右子树插入致使的class
操做方法:左旋import
(2)不平衡是因为对K的左孩子的左子树插入致使的二叉树
操做方法:右旋搜索
(3)不平衡是因为对K的右孩子的左子树插入致使的循环
操做方法:右旋——左旋
(4)不平衡是因为对K的左孩子的右子树插入致使的
操做方法:左旋——右旋
from .bst import BiTreeNode, BST class AVLNode(BiTreeNode): def __init__(self, data): BiTreeNode.__init__(self, data) self.bf = 0 # 平衡因子,bf=-1:左边树比右边高;bf=1:右边树比左边高 class AVLTree(BST): def __init__(self, li=None): BST.__init__(self, li) def insert_no_rec(self, val): """重写插入方法""" def rotate_left(self, p, c): # 根节点及其右孩子 """对K的右孩子的右子树插入致使——左旋""" s2 = c.lchild p.rchild = s2 if s2: # 若是s2不为空 s2.parent = p # C与P连接起来 c.lchild = p p.parent = c # 更新平衡因子 p.bf = 0 c.bf = 0 return c # 根节点 def rotate_right(self, p, c): """对K的左孩子的左子树插入致使——右旋""" s2 = c.rchild p.lchild = s2 if s2: s2.parent = p # C与P连接起来 c.rchild = p p.parent = c # 更新平衡因子 p.bf = 0 c.bf = 0 return c def rotate_right_left(self, p, c): """因为对K的右孩子的左子树插入致使——右旋左旋""" g = c.lchild # g节点是c的左孩子 # 右旋 s3 = g.rchild c.lchild = s3 # c的左孩子绑定s3 if s3: # 若是s3存在 s3.parent = c # s3的父节点指向c(反链回去) # G与C连接起来 g.rchild = c c.parent = g # 左旋 s2 = g.lchild p.rchild = s2 # s2绑定给p的右孩子 if s2: # 若是s2存在 s2.parent = p # G与P连接起来 g.lchild = p p.parent = g # 更新平衡因子 if g.bf > 0: # 插入的是s3,原G的右孩子 p.bf = -1 # p节点右边是空的 c.bf = 0 elif g.bf < 0: # 插入的是s2,原G的左孩子 p.bf = 0 c.bf = 1 # c节点左边是空的 else: # 插入的是G p.bf = 0 c.bf = 0 def rotate_left_right(self, p, c): """因为对K的左孩子的右子树插入致使——左旋右旋""" g = c.rchild # g节点是c的右孩子 # 左旋 s2 = g.lchild c.rchild = s2 # c的右孩子绑定s2 if s2: # 若是s3存在 s2.parent = c # s2的父节点指向c(反链回去) # G与C连接起来 g.lchild = c c.parent = g # 右旋 s3 = g.rchild p.lchild = s3 # s3绑定给p的左孩子 if s3: # 若是s3存在 s3.parent = p # G与P连接起来 g.rchild = p p.parent = g # 更新平衡因子 if g.bf < 0: # 插入的是s2,原G的左孩子 p.bf = 1 c.bf = 0 elif g.bf > 0: # 插入的是s3,原G的右孩子 p.bf = 0 c.bf = -1 else: # 插入的是G p.bf = 0 c.bf = 0
from bst import BiTreeNode, BST class AVLNode(BiTreeNode): def __init__(self, data): BiTreeNode.__init__(self, data) self.bf = 0 # 平衡因子,bf=-1:左边树比右边高;bf=1:右边树比左边高 class AVLTree(BST): def __init__(self, li=None): BST.__init__(self, li) def rotate_left(self, p, c): # 根节点及其右孩子 """代码省略""" def rotate_right(self, p, c): """代码省略""" def rotate_right_left(self, p, c): """代码省略""" def rotate_left_right(self, p, c): """代码省略""" def insert_no_rec(self, val): """重写BST插入方法""" # 1.第一步和BST同样作插入 p = self.root if not p: # 空树的状况处理 self.root = AVLNode(val) return while True: if val < p.data: # 添加值小于当前节点,往左边走 if p.lchild: # 若是左孩子存在 p = p.lchild else: # 左子树不存在 p.lchild = AVLNode(val) p.lchild.parent = p node = p.lchild # node保存插入的节点 break elif val > p.data: # 大于根节点往右边走 if p.rchild: # 若是右孩子存在 p = p.rchild else: # 右子树不存在 p.rchild = AVLNode(val) p.rchild.parent = p node = p.rchild # node保存插入的节点 break else: # 有一个同样值的节点,什么都不作 return # 2.第二步更新平衡因子 while node.parent: # 若是node的父亲不是空 if node.parent.lchild == node: # 传递是从左子树来的,左子树更沉了 # 更新node.parent的平衡因子 -= 1 if node.parent.bf < 0: # 原来node.parent.bf==-1,更新后变为-2 # 作旋转 # 看node哪边沉 g = node.parent.parent # 用于链接旋转以后的子树 x = node.parent # 旋转前子树的根 if node.bf > 0: # node右边沉——》左右 n = self.rotate_left_right(node.parent, node) else: # node左边沉——》左左 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左边沉——》右左 n = self.rotate_right_left(node.parent, node) else: # node右边沉——》右右 n = self.rotate_left(node.parent, node) # 这里不考虑等于0的状况,由于传递上来了,确定是由于它的bf不为0 # 记得连起来 elif node.parent.bf < 0: # 原来node.parent.bf==-1,更新后变为0 node.parent.bf = 0 break # 由于是0,就不须要传递了 else: # 原来node.parent.bf == 0,更新后变为1 node.parent.bf = 1 node = node.parent # 往上走一层继续循环 continue # 连接旋转后的子树 n.parent = g if g: # 若是g不是空 if x == g.lchild: # 若是旋转以前子树的根(x)是g的左孩子 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("") tree.in_order(tree.root) """ 6,4,2,1,3,5,8,7,9, 1,2,3,4,5,6,7,8,9, """