AVL树的python实现
AVL树是带有平衡条件的二叉查找树,一般要求每个节点的左子树和右子树的高度最多差1(空树的高度定义为-1)。
在高度为h的AVL树中,最少的节点数S(h)由S(h)=S(h-1)+S(h-2)+1得出,其中S(0)=1,S(1)=2。
如上图,分别为高度为0,1,2,3的AVL树所需要的最少节点数。
1.AVL树的实现,遍历与查找操作与二叉查找树相同。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | class Node( object ): def __init__( self ,key): self .key = key self .left = None self .right = None self .height = 0 class AVLTree( object ): def __init__( self ): self .root = None def find( self ,key): if self .root is None : return None else : return self ._find(key, self .root) def _find( self ,key,node): if node is None : return None elif key<node.key: return self ._find(key, self .left) elif key>node.key: return self ._find(key, self .right) else : return node def findMin( self ): if self .root is None : return None else : return self ._findMin( self .root) def _findMin( self ,node): if node.left: return self ._findMin(node.left) else : return node def findMax( self ): if self .root is None : return None else : return self ._findMax( self .root) def _findMax( self ,node): if node.right: return self ._findMax(node.right) else : return node def height( self ,node): if node is None : return - 1 else : return node.height |
2.AVL树的插入操作
插入一个节点可能会破坏AVL树的平衡,可以通过旋转操作来进行修正。
插入一个节点后,只有从插入节点到根节点的路径上的节点的平衡可能被改变。我们需要找出第一个破坏了平衡条件的节点,称之为K。K的两颗子树的高度差2。
不平衡有四种情况:
1.对K的左儿子的左子树进行一次插入
2.对K的左儿子的右子树进行一次插入
3.对K的右儿子的左子树进行一次插入
4.对K的右儿子的右子树进行一次插入
情况1与4是对称的,需要进行一次单旋转操作,清况2与3需要一次双旋转操作。
情况1:
1 2 3 4 5 6 7 | def singleLeftRotate( self ,node): k1 = node.left node.left = k1.right k1.right = node node.height = max ( self .height(node.right), self .height(node.left)) + 1 k1.height = max ( self .height(k1.left),node.height) + 1 return k1 |
情况4:
1 2 3 4 5 6 7 | def singleRightRotate( self ,node): k1 = node.right node.right = k1.left k1.left = node node.height = max ( self .height(node.right), self .height(node.left)) + 1 k1.height = max ( self .height(k1.right),node.height) + 1 return k1 |
情况3:
相当于进行了两次单旋转。
1 2 3 | def doubleRightRotate( self ,node): node.right = self .singleLeftRotate(node.right) return self .singleRightRotate(node) |
情况2:
与情况3类似,都是进行了2次单旋转。
1 2 3 | def doubleLeftRotate( self ,node): node.left = self .singleRightRotate(node.left) return self .singleLeftRotate(node) |
一系列插入操作:
插入代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | def put( self ,key): if not self .root: self .root = Node(key) else : self .root = self ._put(key, self .root) def _put( self ,key,node): if node is None : node = Node(key) elif key<node.key: node.left = self ._put(key,node.left) if ( self .height(node.left) - self .height(node.right)) = = 2 : if key<node.left.key: node = self .singleLeftRotate(node) else : node = self .doubleLeftRotate(node) elif key>node.key: node.right = self ._put(key,node.right) if ( self .height(node.right) - self .height(node.left)) = = 2 : if key<node.right.key: node = self .doubleRightRotate(node) else : node = self .singleRightRotate(node) node.height = max ( self .height(node.right), self .height(node.left)) + 1 return node |
3.AVL树的删除操作:
删除操作比较复杂,如有错误,请指正。
1.当前节点为要删除的节点且是树叶(无子树),直接删除,当前节点(为None)的平衡不受影响。
2.当前节点为要删除的节点且只有一个左儿子或右儿子,用左儿子或右儿子代替当前节点,当前节点的平衡不受影响。
3.当前节点为要删除的节点且有左子树右子树:如果右子树高度较高,则从右子树选取最小节点,将其值赋予当前节点,然后删除右子树的最小节点。如果左子树高度较高,则从左子树选取最大节点,将其值赋予当前节点,然后删除左子树的最大节点。这样操作当前节点的平衡不会被破坏。
4.当前节点不是要删除的节点,则对其左子树或者右子树进行递归操作。当前节点的平衡条件可能会被破坏,需要进行平衡操作。
如上图,25为当前节点,左子树删除17后平衡条件被破坏,需要根据当前节点(25)的右子树(30)的左子树(28)高度是否高于右子树(35)的高度进行判断,若高于,进行双旋转,否则进行单旋转
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | def delete( self ,key): self .root = self .remove(key, self .root) def remove( self ,key,node): if node is None : raise KeyError, 'Error,key not in tree' elif key<node.key: node.left = self .remove(key,node.left) if ( self .height(node.right) - self .height(node.left)) = = 2 : if self .height(node.right.right)> = self .height(node.right.left): node = self .singleRightRotate(node) else : node = self .doubleRightRotate(node) node.height = max ( self .height(node.left), self .height(node.right)) + 1 elif key>node.key: node.right = self .remove(key,node.right) if ( self .height(node.left) - self .height(node.right)) = = 2 : if self .height(node.left.left)> = self .height(node.left.right): node = self .singleLeftRotate(node) else : node = self .doubleLeftRotate(node) node.height = max ( self .height(node.left), self .height(node.right)) + 1 elif node.left and node.right: if node.left.height< = node.right.height: minNode = self ._findMin(node.right) node.key = minNode.key node.right = self .remove(node.key,node.right) else : maxNode = self ._findMax(node.left) node.key = maxNode.key node.left = self .remove(node.key,node.left) node.height = max ( self .height(node.left), self .height(node.right)) + 1 else : if node.right: node = node.right else : node = node.left return node |
全部代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | class Node( object ): def __init__( self ,key): self .key = key self .left = None self .right = None self .height = 0 class AVLTree( object ): def __init__( self ): self .root = None def find( self ,key): if self .root is None : return None else : return self ._find(key, self .root) def _find( self ,key,node): if node is None : return None elif key<node.key: return self ._find(key, self .left) elif key>node.key: return self ._find(key, self .right) else : return node def findMin( self ): if self .root is None : return None else : return self ._findMin( self .root) def _findMin( self ,node): if node.left: return self ._findMin(node.left) else : return node def findMax( self ): if self .root is None : return None else : return self ._findMax( self .root) def _findMax( self ,node): if node.right: return self ._findMax(node.right) else : return node def height( self ,node): if node is None : return - 1 else : return node.height def singleLeftRotate( self ,node): k1 = node.left node.left = k1.right k1.right = node node.height = max ( self .height(node.right), self .height(node.left)) + 1 k1.height = max ( self .height(k1.left),node.height) + 1 return k1 def singleRightRotate( self ,node): k1 = node.right node.right = k1.left k1.left = node node.height = max ( self .height(node.right), self .height(node.left)) + 1 k1.height = max ( self .height(k1.right),node.height) + 1 return k1 def doubleLeftRotate( self ,node): node.left = self .singleRightRotate(node.left) return self .singleLeftRotate(node) def doubleRightRotate( self ,node): node.right = self .singleLeftRotate(node.right) return self .singleRightRotate(node) def put( self ,key): if not self .root: self .root = Node(key) else : self .root = self ._put(key, self .root) def _put( self ,key,node): if node is None : node = Node(key) elif key<node.key: node.left = self ._put(key,node.left) if ( self .height(node.left) - self .height(node.right)) = = 2 : if key<node.left.key: node = self .singleLeftRotate(node) else : node = self .doubleLeftRotate(node) elif key>node.key: node.right = self ._put(key,node.right) if ( self .height(node.right) - self .height(node.left)) = = 2 : if key<node.right.key: node = self .doubleRightRotate(node) else : node = self .singleRightRotate(node) node.height = max ( self .height(node.right), self .height(node.left)) + 1 return node def delete( self ,key): self .root = self .remove(key, self .root) def remove( self ,key,node): if node is None : raise KeyError, 'Error,key not in tree' elif key<node.key: node.left = self .remove(key,node.left) if ( self .height(node.right) - self .height(node.left)) = = 2 : if self .height(node.right.right)> = self .height(node.right.left): node = self .singleRightRotate(node) else : node = self .doubleRightRotate(node) node.height = max ( self .height(node.left), self .height(node.right)) + 1 elif key>node.key: node.right = self .remove(key,node.right) if ( self .height(node.left) - self .height(node.right)) = = 2 : if self .height(node.left.left)> = self .height(node.left.right): node = self .singleLeftRotate(node) else : node = self .doubleLeftRotate(node) node.height = max ( self .height(node.left), self .height(node.right)) + 1 elif node.left and node.right: if node.left.height< = node.right.height: minNode = self ._findMin(node.right) node.key = minNode.key node.right = self .remove(node.key,node.right) else : maxNode = self ._findMax(node.left) node.key = maxNode.key node.left = self .remove(node.key,node.left) node.height = max ( self .height(node.left), self .height(node.right)) + 1 else : if node.right: node = node.right else : node = node.left return node |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)