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, """