【Python数据结构】——二叉平衡树AVL(查找、构建、删除、插入、打印、遍历)
生活随笔
收集整理的這篇文章主要介紹了
【Python数据结构】——二叉平衡树AVL(查找、构建、删除、插入、打印、遍历)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2021/7/28 20:57
# @Author : @linlianqin
# @Site :
# @File : 二叉平衡樹專題(創建、插入、查找).py
# @Software: PyCharm
# @description:'''二叉平衡樹的特點:在二叉查找樹的基礎上對每一個節點的左右子樹的高度進行了規定——每一個節點的左右子樹的高度差不超過1
1)任何一個節點都有:左子樹節點值 <= 節點值 < 右子樹節點值
2)任何一個節點的左子樹高度和右子樹高度之差不超過1兩個概念:
1)當前節點的高度 = max(左子樹節點高度,右子樹節點高度) + 1
2)平衡因子 = 左子樹節點高度 - 右子樹節點高度調式代碼過程中出現的問題:
1)高度值混淆:高度值規定——空樹高度為0,默認節點高度值為1,葉節點的高度值默認為1;
2)注意插入方法和二叉查找樹的插入方法的區別:
BST的插入過程中,頭節點是不會發生改變的,因為只需要滿足左<=中<右即可;
AVL的插入過程中,由于要維持樹的平衡,同時要滿足BST的性質,因此再插入過程中,各個子樹的根節點是會發生改變的,因此插入結束后,需要將最新的頭節點返回,以便后續的遍歷
3)在更新節點高度值的時候,設計更新節點高度值函數的時候沒有更新節點的高度值,而是直接返回了,
導致節點高度值出現錯誤
錯誤代碼:return max(self.getTreeHeight(root.left),self.getTreeHeight(root.right))+1
正確代碼:root.height = max(self.getTreeHeight(root.left),self.getTreeHeight(root.right))+1
4)插入元素后,在進行左旋\右旋的時候,沒有接受返回來的調整平衡后的子樹根節點,導致最后遍歷AVL樹的時候元素不完整
錯誤代碼:self.AVL_L(root.left)
正確代碼:root.left = self.AVL_L(root.left)'''# 定義二叉平衡樹的節點類,比普通的二叉樹節點類多了一個高度屬性
class TreeNode:def __init__(self,val,left=None,right=None,height=1):self.val = valself.left = leftself.right = rightself.height = height# 二叉平衡樹的基本操作
class AVL_ops:# 計算以當前節點為根節點的樹的高度def getTreeHeight(self,root):if root == None:return 0return root.height# 更新以當前節點為根節點的樹的高度 = max(左子樹節點高度,右子樹節點高度) + 1def updateTreeHeight(self,root):## 這里不需要判斷左右節點是否為空,是因為在self.getTreeHeight函數中已經將空節點的高度設置為0了root.height = max(self.getTreeHeight(root.left),self.getTreeHeight(root.right))+1# 計算當前節點的平衡因子 = (左子樹節點高度 - 右子樹節點高度)def getNodeBalanceFactor(self,root):return self.getTreeHeight(root.left)- self.getTreeHeight(root.right)# 在二叉平衡樹中的查找目標值—-因為AVL實際上是BST因此查找也是一樣的def AVL_search(self,root,target):# 訪問到了空樹的時候,說明目標值不存在if root is None:return False# 相等說明目標值存在if target == root.val:return True# 目標值在當前節點的左子樹上if target < root.val:return self.AVL_search(root.left,target)# 目標值在當前節點的右子樹上if target > root.val:return self.AVL_search(root.right,target)# 在二叉平衡樹中進行插入——和BST的插入有所區別,這里是因為需要保證樹的高度處于平衡狀態## 插入一個元素后,高度失去平衡的節點的平衡因子一定是2或者-2只需要將這里的失衡的節點調節就可以## 事實證明:只需要將失衡的節點進行調節整棵樹就可以達到平衡狀態## 這里分為左旋和右旋兩種方式進行平衡調節,對于失衡的樹有LL,LR,RR,RL四種結構## 其中LL右旋達到平衡、LR先左節點左旋為LL再右旋、RR左旋達到平衡、RL先右節點右旋為RR然后再達到平衡### 左旋:def AVL_L(self,root):# 1)臨時節點存放根節點的右節點temp = root.right# 2)將根節點的右節點更新為temp的左節點root.right = temp.left# 3)將temp節點的左節點更新為根節點temp.left = root# 4)更新temp和root的高度值self.updateTreeHeight(root)self.updateTreeHeight(temp)# 5)更新根節點root = tempreturn root### 右旋:和左旋相反def AVL_R(self,root):# 1)臨時節點存放根節點的左節點temp = root.left# 2)將根節點的左節點更新為temp的右節點root.left = temp.right# 3)將temp節點的右節點更新為根節點temp.right = root# 4)更新temp和root的高度值self.updateTreeHeight(root)self.updateTreeHeight(temp)# 5)更新根節點root = tempreturn root# 插入的話首先需要進行失衡節點處的樹型判斷LL\LR\RR\RL# 步驟:# 1)先將元素按照左小右大的性質插入到對應葉節點末尾;# 2)再更新插入元素后的各節點高度;# 3)根據各節點高度值計算各節點的平衡因子;# 4)根據節點及其左右子節點的平衡因子來判斷樹形;# 5)根據樹形選擇左旋、右旋組合來將插入后的失衡二叉樹調整至平衡二叉樹AVL# 6)返回最新的根節點完成插入操作def AVL_insert(self,root,target):if root is None:return TreeNode(target)# target插入到左子樹,說明左子樹會出現失衡,樹形可能為LL或者LRif root.val > target:root.left = self.AVL_insert(root.left,target)# 更新樹高self.updateTreeHeight(root)# 判斷樹形if self.getNodeBalanceFactor(root) == 2:# LL型,右旋if self.getNodeBalanceFactor(root.left) == 1:root = self.AVL_R(root)# LR型,右旋elif self.getNodeBalanceFactor(root.left) == -1:root.left = self.AVL_L(root.left)root = self.AVL_R(root)# target插入到右子樹,說明右子樹會出現失衡,樹形可能為RR或者RLelse:root.right = self.AVL_insert(root.right, target)# 更新樹高self.updateTreeHeight(root)# 判斷樹形if self.getNodeBalanceFactor(root) == -2:# RR型,左旋if self.getNodeBalanceFactor(root.right) == -1:root = self.AVL_L(root)# RL型,先對右節點右旋再對根節點左旋elif self.getNodeBalanceFactor(root.right) == 1:root.right = self.AVL_R(root.right)root = self.AVL_L(root)return root# todo:刪除元素,其實就是插入的反向操作def AVL_delete(self,root,target):pass# AVL創建——其實就是一個一個插入元素def AVL_create(self,nums):if len(nums) == 0:return Noneroot = TreeNode(nums[0])for num in nums[1:]:root = self.AVL_insert(root,num)return root# 層序遍歷AVLdef AVL_layer(self,root):if root is None:returnq = [root]Height = []while q:newQ = []for node in q:print(node.val,end=',')Height.append(node.height)if node.left is not None:newQ.append(node.left)if node.right is not None:newQ.append(node.right)q = newQprint("\n對應節點的高度")print(Height)# 中序# 遍歷二叉查找數,中序遍歷def AVL_mid_scan(self,root):if root is None:return# 遍歷左子樹self.AVL_mid_scan(root.left)# 遍歷根節點print(root.val, end=',')self.AVL_mid_scan(root.right)li = [1,2,3,4,5,6,7]
print("原始列表:",li)# 創建
print("創建AVL")
root = AVL_ops().AVL_create(li)
# 層序遍歷
print("層序遍歷")
AVL_ops().AVL_layer(root)
print("中序遍歷")
AVL_ops().AVL_mid_scan(root)print("\n插入數值-1")
root = AVL_ops().AVL_insert(root,-1)
print("插入數值-1后的層序遍歷")
AVL_ops().AVL_layer(root)
print("插入數值-1后的中序遍歷")
AVL_ops().AVL_mid_scan(root)print("\n插入數值5")
root = AVL_ops().AVL_insert(root,-1)
print("插入數值5后的層序遍歷")
AVL_ops().AVL_layer(root)
print("插入數值5后的中序遍歷")
AVL_ops().AVL_mid_scan(root)
示例結果:
原始列表: [1, 2, 3, 4, 5, 6, 7]
創建AVL
層序遍歷
4,2,6,1,3,5,7,
對應節點的高度
[3, 2, 2, 1, 1, 1, 1]
中序遍歷
1,2,3,4,5,6,7,
插入數值-1
插入數值-1后的層序遍歷
4,2,6,1,3,5,7,-1,
對應節點的高度
[4, 3, 2, 2, 1, 1, 1, 1]
插入數值-1后的中序遍歷
-1,1,2,3,4,5,6,7,
插入數值5
插入數值5后的層序遍歷
4,2,6,-1,3,5,7,-1,1,
對應節點的高度
[4, 3, 2, 2, 1, 1, 1, 1, 1]
插入數值5后的中序遍歷
-1,-1,1,2,3,4,5,6,7,
注意和二叉查找樹的細節區別,細節區別見本文代碼前部分《遇到的問題》
總結
以上是生活随笔為你收集整理的【Python数据结构】——二叉平衡树AVL(查找、构建、删除、插入、打印、遍历)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 深入浅出etcd系列 – 心跳和选举
- 下一篇: 【Python数据结构】——并查集的实现