AVL樹插入的python實現
阿新 • • 發佈:2022-04-11
AVL樹的插入python實現
-
AVL樹:AVL樹是一棵自平衡的二叉搜素樹
-
AVL樹有以下性質:
- 根的左右子樹的高度之差的絕對值不超過1
- 根的左右子樹都是平衡二叉樹
-
插入一個節點可能會破壞AVL樹的平衡,可以通過旋轉操作來進行修正
-
插入一個節點後,只有從插入節點到根節點的路徑上的節點的平衡可能改變。我們需要找出第一個破壞了平衡條件的節點,稱之為k,k的兩個子樹的高度差為2
-
不平衡的出現可能有四種情況
-
左旋:不平衡是由對K的右孩子的右子樹插入導致的:左旋
-
右旋:不平衡是由於對k的左孩子的左子樹插入導致的:右旋
-
右旋-左旋:不平衡是由於對k的右孩子的左子樹插入導致的:右旋-左旋
-
左旋-右旋:不平衡是由於對k的左孩子的右子樹插入導致的:左旋-右旋
-
程式碼實現
class AVLNode: def __init__(self,data): self.data = data self.rchild = None self.lchild = None self.parent = None self.bf=0 #bf為平衡值,預設為0,插入右孩子時bf+1,插入左孩子時bf-1 class AVLTree: def __init__(self,li=None): self.root=None #迴圈插入AVL樹 if li: for val in li: self.insert_no_rec(val) 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):#右旋-左旋: 不平衡是由於對k的右孩子的左子樹插入導致的 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:#往右偏 c.bf=0 p.bf=-1 elif g.bf<0: #插入到s2中 c.bf=1 p.bf=0 else:#s1,s2,s3,s4都是空 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 if g.bf>0: #右邊多 p.bf=0 c.bf=-1 elif g.bf<0:#左邊多 c.bf=0 p.bf=1 else: c.bf=0 p.bf=0 g.bf=0 return g def pre_order(self, root): # 前序遍歷 if root: print(root.data, end=',') self.pre_order(root.lchild) self.pre_order(root.rchild) def in_order(self, root): # 中序遍歷 if root: self.in_order(root.lchild) print(root.data, end=',') self.in_order(root.rchild) def post_order(self, root): # 後序遍歷 if root: self.post_order(root.lchild) self.post_order(root.rchild) print(root.data, end=',') def insert_no_rec(self,val): #插入 p=self.root #當根節點不存在時,插入的點即為根節點 if not p: self.root=AVLNode(val) return #當根節點存在時 while True: #如果值小於當前節點的值,則查詢他的左孩子,如果左孩子存在,則另左孩子節點為當前節點,進入下次插入,如果左孩子不存在,則將插入節點插入到當前節點的左孩子,並使當前節點的bf-1 if val< p.data: if p.lchild: p=p.lchild else: p.lchild=AVLNode(val) p.lchild.parent=p node=p.lchild p.bf=p.bf-1 break #如果值大於當前節點的值,則查詢他的右孩子,如果右孩子存在,則令右孩子節點為當前節點,進行下一次插入,如果右孩子不存在,則將插入節點插入到當前節點的右孩子,使當前節點的bf+1 elif val > p.data: if p.rchild: p =p.rchild else: p.rchild=AVLNode(val) p.rchild.parent=p node=p.rchild p.bf=p.bf+1 break else: return #2.更新balance factor #p為當前節點,p.parent存在即當前節點不是根節點時 while p.parent:#node.parent不空 if p.parent.lchild==p:#傳遞是從左子樹開始 if p.parent.bf== -1: #原來的p.parent.bf==-1,更新後為-2 #記錄當前節點的父親節點和祖父節點,以便後面的連結 head=p.parent.parent tmp=p.parent #插入節點後,當前節點有三種狀態,只有左孩子,只有右孩子,左右孩子都有,對應了三種不同的結果 if p.bf>0:#只有右孩子時,發生左旋-右旋 n=self.rotate_left_right(p.parent,p) elif p.bf<0:#只有左孩子時,發生右旋 n=self.rotate_right(p.parent,p) else: break elif p.parent ==1: #原來的p.parent.bf==1,更新後變為0 #當前節點只有一個孩子節點時/或平衡點不為0時,當前節點的父親節點bf=0 if p.bf ==0: break else: p.parent.bf=0 break else:#當前節點父親節點bf=0,當前節點只有一個孩子節點時/或平衡點不為0時,當前節點的父親節點bf=-1,並將問題向上傳遞 if p.bf==0: break else: p.parent.bf=-1 p=p.parent continue else:#右子樹插入 if p.parent.bf ==1: head = p.parent.parent tmp = p.parent if p.bf<0:#右子樹的左孩子插入 n=self.rotate_right_left(p.parent,p) elif p.bf>0: n=self.rotate_left(p.parent,p) else: break elif p.parent.bf == -1: if p.bf==0: break else: p.parent.bf=0 else: if p.bf==0: break else: p.parent.bf=1 p=p.parent continue n.parent=head if head: # head不是空 if tmp == head.lchild: head.lchild = n else: head.rchild = n break else: self.root = n break