阅读更多
1 前言
AVL-tree是一种平衡二叉树,搜索的平均复杂度是O(log n)。本篇博客将介绍AVL-tree的两种实现方式,其中第二种方式是参考<STL源码剖析>,较第一种方式更为简单高效,推荐第二种方式
2 定义
在计算机科学中,AVL树是最先发明的自平衡二叉查找树。在AVL树中任何节点的两个子树的高度最大差别为一,所以它也被称为高度平衡树。查找、插入和删除在平均和最坏情况下都是O(log n)。增加和删除可能需要通过一次或多次树旋转来重新平衡这个树
节点的属性
- val:节点的值
- left:节点的左孩子
- right:节点的右孩子
- parent:节点的双亲
- height:节点的高度
- 相比于普通的搜索二叉树,AVL树额外维护了一个高度属性,因为AVL树通过该高度属性来判断树的平衡性
平衡性质
- 每个节点的左子树与右子树的高度最多不超过1
- 节点的高度:从给定节点到其最深叶节点所经过的边的数量
3 版本1
3.1 平衡性破坏分析
为了方便描述,定义几个符号
- 对于一个节点X,调整(这里的调整特指旋转)之前其高度记为Hx
- 仍然对于上述节点X,调整一次后高度记为Hx+
3.1.1 可旋性分析
首先分析左旋,见如下示意图
问题1:何时我们会进行左旋操作
只有当右子树的高度大于左子树的高度才会有左旋的需求。以上图为例,即HD=HA-1或HD=HA-2
问题2:何时左旋后能够达到平衡状态
只有HC >= HE时,旋转后该子树的所有节点才满足AVL树的性质
下面对于问题2的结论进行分析
- 旋转前,各节点高度如下
- HD=HA-1或HD=HA-2
- HC=HA-1
- HE=HA-1或HE=HA-2
- 旋转后,各节点高度如下
- HD+=HD=HA-1或HA-2
- HE+=HE=HA-1或HA-2
- HC+=HC=HA-1
- 旋转后,B节点平衡,HB+=HA或HB+=HA-1
- 旋转后,A节点平衡,HA+=HA或HA+=HA+1
然后分析右旋,见如下示意图
问题1:何时我们会进行右旋操作
只有当左子树的高度大于右子树的高度才会有右旋的需求。以上图为例,即HC=HB-1或HC=HB-2
问题2:何时右旋后能够达到平衡状态
只有HD >= HE时,旋转后该子树的所有节点才满足AVL树的性质
下面对于问题2的结论进行分析
- 旋转前,各节点高度如下
- HC=HB-1或HC=HB-2
- HD=HB-1
- HE=HB-1或HE=HB-2
- 旋转后,各节点高度如下
- HD+=HD=HB-1
- HE+=HE=HB-1或HB-2
- HC+=HC=HB-1或HB-2
- 旋转后,A节点平衡,且HA+=HB或HA+=HB-1
- 旋转后,B节点平衡,且HB+=HB或HB+=HB+1
注意:上述分析仅仅讨论了左旋或者右旋一棵子树时,旋转后该子树是否平衡,但是旋转后该子树的高度是可能变化的,也就是对于该子树的父节点而言,可能又会造成不平衡。因此在AVL性质维护函数中需要充分考虑到这一点
3.1.2 平衡性的维护
当平衡性质被破坏需要右旋来维护性质时
当C为平衡被破坏的节点,且C的左子树比右子树的高度大2,示意图如下
- 需要对C进行一次右旋
- 右旋的前提是HB >= HD
- 若不满足HB >= HD,则需要首先对A进行一次左旋,而左旋又存在前提
- 一直往下递归,直至满足旋转条件
其实,以上的过程存在一个可以优化的点:
假设对C节点的右旋条件不满足,即HB < HD,那么此时需要对A节点进行一次左旋。但是A节点左旋后可能会导致A子树的高度发生变化(可能A节点的高度比旋转前少1)。如果A子树的高度少1,那么对于节点C就成为一个平衡节点了,就不需要再进行右旋操作了。但是对于下面将要讲的伪代码中,并没有进行这样的优化。也就意味着不管A子树的高度是否发生变化,C的右旋仍然会执行,这样做并不会破坏平衡性(旋转前后都会处于平衡状态),只是复杂度增高了
当平衡性质被破坏需要左旋来维护性质时
当A为平衡被破坏的节点,且A的右子树比左子树的高度大2,示意图如下
- 需要对A进行一次左旋
- 左旋的前提是HE >= HD
- 若不满足HE >= HD,则需要首先对C进行一次右旋,而右旋又存在前提
- 一直往下递归,直至满足旋转条件
这里存在一个相同的优化点,不再赘述
3.2 伪代码
3.2.1 基本操作
更新指定节点的高度,只有当该节点的左右孩子节点的高度都正确时,才能得到正确的结果
1 2 3 4
| AVL-TREE-HEIGHT(T,x) if x.left.height≥x.right.height x.height=x.left.height+1 else x.height=x.right.height+1
|
将一棵子树替换掉另一棵子树
1 2 3 4 5 6 7
| AVL-TREE-TRANSPLANT(T,u,v) if u.p==T.nil T.root=v elseif u==u.p.left u.p.left=v else u.p.right=v v.p=u.p
|
3.2.2 左旋和右旋
左旋给定节点,更新旋转后节点的高度,并返回旋转后子树的根节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| AVL-TREE-LEFT-ROTATE(T,x) y=x.right x.right=y.left if y.left≠T.nil y.left.p=x y.p=x.p if x.p== T.nil T.root=y elseif x==x.p.left x.p.left=y else x.p.right=y y.left=x x.p=y AVL-TREE-HEIGHT(T,x) AVL-TREE-HEIGHT(T,y)
return y
|
右旋给定节点,更新旋转后节点的高度,并返回旋转后子树的根节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| AVL-TREE-RIGH-TROTATE(T,y) x=y.left y.left=x.right if x.right≠T.nil x.right.p=y x.p=y.p if y.p==T.nil root=x elseif y==y.p.left y.p.left=x else y.p.right=x x.right=y y.p=x AVL-TREE-HEIGHT(T,y) AVL-TREE-HEIGHT(T,x)
return x
|
3.2.3 性质维护
根据指定方向旋转给定节点,旋转后该子树满足平衡的性质,并且输入的节点必须满足如下性质
X节点必定是以X为根节点的子树中唯一不满足平衡性的节点。意味着X节点的孩子子树的所有节点均满足平衡性。因此,必须从下往上找到第一个不平衡的节点来调用该方法
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
| AVL-TREE-HOLD-ROTATE(T,x,orientation) let stack1,stack2 be two stacks stack1.push(x) stack2.push(orientation) cur=Nil rotateRoot=Nil curOrientation=INVALID; while(!stack1.Empty()) cur=stack1.top() curOrientation=stack2.top() if curOrientation==LEFT if cur.right.right.height≥cur.right.left.height stack1.pop() stack2.pop() rotateRoot=AVL-TREE-LEFT-ROTATE(T,cur) else stack1.push(cur.right) stack2.push(RIGHT); elseif curOrientation ==RIGHT if cur.left.left.height≥cur.left.right.height stack1.pop() stack2.pop() rotateRoot=AVL-TREE-RIGHT-ROTATE(T,cur) else stack1.push(cur.left) stack2.push(LEFT) return rotateRoot
|
3.2.4 插入
插入一个节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| AVL-TREE-TREE-INSERT(T,z) y=T.nil x=T.root while x≠T.nil y=x if z.key<x.key x=x.left else x=x.right z.p=y if y==T.nil T.root=z elseif z.key<y.key y.left=z else y.right=z z.left=T.nil z.right=T.nil AVL-TREE-FIXUP(T,z)
|
从指定节点向上遍历查找不平衡的节点,并维护平衡树的性质
1 2 3 4 5 6 7 8 9 10
| AVL-TREE-FIXUP(T,y) if y==T.nil y=y.p while(y≠T.nil) AVL-TREE-HEIGHT(y) if y.left.height==y.right.height+2 y= AVL-TREE-HOLD-ROTATE(T,y,2) elseif y.right.height=y.left.height+2 y= AVL-TREE-HOLD-ROTATE(T,y,1) y=y.p
|
3.2.5 删除
删除一个节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| AVL-TREE-DELETE(T,z) y=z if z.left==T.nil x=y.right AVL-TREE-TRANSPLANT(T,z,z.right) elseif z.right==T.nil x=y.left AVL-TREE-TRANSPLANT(T,z,z.left) else y=AVL-TREE-MINIMUM(z.right) x=y.right if y.p==z x.p=y else AVL-TREE-TRANSPLANT (T,y,y.right) y.right=z.right y.right.p=y AVL-TREE-TRANSPLANT (T,z,y) y.left=z.left y.left.p=y AVL-TREE-FIXUP(T,x)
|
4 版本2
与版本1的实现不同,这个版本的分析将会更加简单,实现效率也会更高
4.1 几类不平衡情况
当插入一个节点后,某节点A为从插入节点往上找到的第一个平衡性被破坏的节点,可以分为如下四种情况,又可分为两大类
- 第一类:外侧
- 插入点位于A的左子节点的左子树–左左
- 插入点位于A的右子节点的右子树–右右
- 第二类:内侧
- 插入点位于A的左子节点的右子树–左右
- 插入点位于A的右子节点的左子树–右左
4.1.1 第一类不平衡(以左左为例)
为了方便描述,定义几个符号
- 对于一个节点X,调整(这里的调整特指旋转)之前其高度记为Hx
- 仍然对于上述节点X,调整一次后高度记为Hx+
插入点位于A的左子节点的左子树–左左,见如下示意图
调整前,各节点的高度如下
- HB=HC+2
- HA=HC+2(为什么A和B高度相同,因为B的高度已经更新过了,而A仍然是是插入新节点之前的高度,即尚未维护A节点的height字段)
- HD=HB-1=HC+1
- HE必定小于HD(否则在新节点插入到节点D为根节点的子树之前,A节点就是不平衡的),因此HE=HC
右旋调整后,各节点的高度如下
- HD+=HD=HC+1
- HE+=HE=HC
- HC+=HC
- 由于HE+=HC+,于是A节点平衡,且HA+=HC+1
- B节点也是平衡的,且HB+=HC+2
可以发现,调整前后子树根节点的高度都是HC+2,因此该节点上层的节点的平衡性不会被破坏,于是通过一次右旋,不平衡性即被消除
4.1.2 第二类不平衡(以左右为例)
为了方便描述,定义几个符号
- 对于一个节点X,调整(这里的调整特指旋转)之前其高度记为Hx
- 仍然对于上述节点X,调整一次后高度记为Hx+
- 仍然对于上述节点X,调整二次后高度记为Hx++
插入点位于A的左子节点的右子树–左右,见如下示意图
调整前,各节点的高度如下
- HB=HC+2
- HA=HC+2(为什么A和B高度相同,因为B的高度已经更新过了,而A仍然是是插入新节点之前的高度,即尚未维护A节点的height字段)
- HE=HB-1=HC+1
- HD必定小于HE,因此HD=HC
- HH与HI至少有一个是HC,另一个可以是HC或HC-1
对B节点进行一次左旋后,各节点高度如下
- HD+=HD=HC
- HH+=HH=HC or HC-1
- HI+=HI=HC or HC-1
- HC+=HC
- HA+=HA=HC+2
- HB+=HC+1
- 当HI+=HC-1时,节点E可能是不平衡的,但是没关系,这只是个中间状态,HE=HC+2
对A节点进行一次右旋,各节点高度如下
- HD++=HD+=HC
- HH++=HH+= HC or HC-1
- HI++=HI+=HC or HC-1
- HC++=HC+=HC
- 旋转后,B节点平衡,HB++=HC+1
- 旋转后,A节点平衡,HA++=HC+1
- 因此旋转后,E节点平衡,HE++=HC+2
可以发现,调整前后子树根节点的高度都是HC+2,因此该节点上层的节点的平衡性不会被破坏,于是通过一次左旋和一次右旋,不平衡性即被消除
4.2 伪代码
4.2.1 基本操作
更新指定节点的高度,只有当该节点的左右孩子节点的高度都正确时,才能得到正确的结果
1 2 3 4
| AVL-TREE-HEIGHT(T,x) if x.left.height≥x.right.height x.height=x.left.height+1 else x.height=x.right.height+1
|
将一棵子树替换掉另一棵子树
1 2 3 4 5 6 7
| AVL-TREE-TRANSPLANT(T,u,v) if u.p==T.nil T.root=v elseif u==u.p.left u.p.left=v else u.p.right=v v.p=u.p
|
4.2.2 左旋和右旋
左旋给定节点,更新旋转后节点的高度,并返回旋转后子树的根节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| AVL-TREE-LEFT-ROTATE(T,x) y=x.right x.right=y.left if y.left≠T.nil y.left.p=x y.p=x.p if x.p== T.nil T.root=y elseif x==x.p.left x.p.left=y else x.p.right=y y.left=x x.p=y AVL-TREE-HEIGHT(T,x) AVL-TREE-HEIGHT(T,y)
return y
|
右旋给定节点,更新旋转后节点的高度,并返回旋转后子树的根节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| AVL-TREE-RIGHT-ROTATE(T,y) x=y.left y.left=x.right if x.right≠T.nil x.right.p=y x.p=y.p if y.p==T.nil root=x elseif y==y.p.left y.p.left=x else y.p.right=x x.right=y y.p=x AVL-TREE-HEIGHT(T,y) AVL-TREE-HEIGHT(T,x)
return x
|
4.2.3 插入
插入一个节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| AVL-TREE-INSERT(T,z) y=T.nil x=T.root while x≠T.nil y=x if z.key<x.key x=x.left else x=x.right z.p=y if y==T.nil T.root=z elseif z.key<y.key y.left=z else y.right=z z.left=T.nil z.right=T.nil AVL-TREE-BALANCE-FIX (T,z)
|
维护平衡性质,分别讨论第一类第二类的四种不平衡情况
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| AVL-TREE--BALANCE-FIX(T,z) originHigh=z.h AVL-TREE-HEIGHT(z) r=z if z.left.h==z.right.h+2 if z.left.left.h>=z.left.right.h r=AVL-TREE-RIGHT-ROTATE(z) elseif z.left.left.h<z.left.right.h AVL-TREE-LEFT-ROTATE(z.left) r=AVL-TREE-RIGHT-ROTATE(z) elseif z.right.h==z.left.h+2 if z.right.right.h>=z.right.left.h r=AVL-TREE-LEFT-ROTATE(z) elseif z.right.right.h<z.right.left.h AVL-TREE-RIGHT-ROTATE(z.right) r=AVL-TREE-LEFT-ROTATE(z) if r.h!=originHigh and r!=root AVL-TREE--BALANCE-FIX(r.parent)
|
4.2.4 删除
删除给定关键字
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| AVL-TREE-DELETE(T,z) y=z p=y.parent if z.left==T.nil AVL-TREE-TRANSPLANT(T,z,z.right) elseif z.right==T.nil AVL-TREE-TRANSPLANT(T,z,z.left) else y=AVL-TREE-MINIMUM(z.right) if y==z.right p=y else p=y.parent AVL-TREE-TRANSPLANT(y,y.right) y.right=z.right y.right.parent=y y.left=z.left y.left.parent=y AVL-TREE-TRANSPLANT (T,z,y) y.height=z.height if p!=nil AVL-TREE--BALANCE-FIX(p)
|
5 Java源码
5.1 节点定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public class AVLTreeNode {
int h;
int val;
AVLTreeNode left, right, parent;
public AVLTreeNode(int val) { h = 0; this.val = val; left = null; right = null; parent = null; } }
|
5.2 版本1
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 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346
| package org.liuyehcf.algorithm.datastructure.tree.avltree;
import java.util.*;
public class AVLTree1 { private enum RotateOrientation { INVALID, LEFT, RIGHT }
private AVLTreeNode root;
private AVLTreeNode nil; private Map<AVLTreeNode, Integer> highMap;
public AVLTree1() { nil = new AVLTreeNode(0); nil.left = nil; nil.right = nil; nil.parent = nil; root = nil; }
public void insert(int val) { AVLTreeNode x = root; AVLTreeNode y = nil; AVLTreeNode z = new AVLTreeNode(val); while (x != nil) { y = x; if (val < x.val) { x = x.left; } else { x = x.right; } } z.parent = y; if (y == nil) { root = z; } else if (z.val < y.val) { y.left = z; } else { y.right = z; } z.left = nil; z.right = nil; fixUp(z); if (!check()) throw new RuntimeException(); }
private void fixUp(AVLTreeNode y) { if (y == nil) { y = y.parent; } while (y != nil) { updateHigh(y); if (y.left.h == y.right.h + 2) y = holdRotate(y, RotateOrientation.RIGHT); else if (y.right.h == y.left.h + 2) y = holdRotate(y, RotateOrientation.LEFT); y = y.parent; } }
private AVLTreeNode holdRotate(AVLTreeNode x, RotateOrientation orientation) { LinkedList<AVLTreeNode> stack1 = new LinkedList<AVLTreeNode>(); LinkedList<RotateOrientation> stack2 = new LinkedList<RotateOrientation>(); stack1.push(x); stack2.push(orientation); AVLTreeNode cur = nil; AVLTreeNode rotateRoot = nil; RotateOrientation curOrientation = RotateOrientation.INVALID; while (!stack1.isEmpty()) { cur = stack1.peek(); curOrientation = stack2.peek(); if (curOrientation == RotateOrientation.LEFT) { if (cur.right.right.h >= cur.right.left.h) { stack1.pop(); stack2.pop(); rotateRoot = leftRotate(cur); } else { stack1.push(cur.right); stack2.push(RotateOrientation.RIGHT); } } else if (curOrientation == RotateOrientation.RIGHT) { if (cur.left.left.h >= cur.left.right.h) { stack1.pop(); stack2.pop(); rotateRoot = rightRotate(cur); } else { stack1.push(cur.left); stack2.push(RotateOrientation.LEFT); } } } return rotateRoot; }
private void updateHigh(AVLTreeNode z) { z.h = Math.max(z.left.h, z.right.h) + 1; }
private AVLTreeNode leftRotate(AVLTreeNode x) { AVLTreeNode y = x.right; x.right = y.left; if (y.left != nil) { y.left.parent = x; } y.parent = x.parent; if (x.parent == nil) { root = y; } else if (x == x.parent.left) { x.parent.left = y; } else { x.parent.right = y; } y.left = x; x.parent = y;
updateHigh(x); updateHigh(y); return y; }
private AVLTreeNode rightRotate(AVLTreeNode y) { AVLTreeNode x = y.left; y.left = x.right; if (x.right != nil) { x.right.parent = y; } x.parent = y.parent; if (y.parent == nil) { root = x; } else if (y == y.parent.left) { y.parent.left = x; } else { y.parent.right = x; } x.right = y; y.parent = x;
updateHigh(y); updateHigh(x); return x; }
private boolean check() { highMap = new HashMap<AVLTreeNode, Integer>(); return checkHigh(root) && checkBalance(root); }
private boolean checkHigh(AVLTreeNode root) { if (root == nil) return true; return checkHigh(root.left) && checkHigh(root.right) && root.h == high(root); }
private int high(AVLTreeNode root) { if (root == nil) { return 0; } if (highMap.containsKey(root)) return highMap.get(root); int leftHigh = high(root.left); int rightHigh = high(root.right); highMap.put(root, Math.max(leftHigh, rightHigh) + 1); return highMap.get(root); }
private boolean checkBalance(AVLTreeNode root) { if (root == nil) { return true; } int leftHigh = root.left.h; int rightHigh = root.right.h; if (Math.abs(leftHigh - rightHigh) == 2) return false; return checkBalance(root.left) && checkBalance(root.right); }
public boolean search(int val) { return search(root, val) != nil; }
private AVLTreeNode search(AVLTreeNode x, int val) { while (x != nil) { if (x.val == val) return x; else if (val < x.val) { x = x.left; } else { x = x.right; } } return nil; }
public void delete(int val) { AVLTreeNode z = search(root, val); if (z == nil) { throw new RuntimeException(); } AVLTreeNode y = z; AVLTreeNode x = nil; if (z.left == nil) { x = y.right; transplant(z, z.right); } else if (z.right == nil) { x = y.left; transplant(z, z.left); } else { y = min(z.right); x = y.right; if (y.parent == z) { x.parent = y; } else { transplant(y, y.right); y.right = z.right; y.right.parent = y; } transplant(z, y);
y.left = z.left; y.left.parent = y;
} fixUp(x); if (!check()) throw new RuntimeException(); }
private void transplant(AVLTreeNode u, AVLTreeNode v) { v.parent = u.parent; if (u.parent == nil) { root = v; } else if (u == u.parent.left) { u.parent.left = v; } else { u.parent.right = v; } }
private AVLTreeNode min(AVLTreeNode x) { while (x.left != nil) { x = x.left; } return x; }
public void inOrderTraverse() { inOrderTraverse(root); System.out.println(); }
public void levelOrderTraversal() { Queue<AVLTreeNode> queue = new LinkedList<AVLTreeNode>(); queue.offer(root); while (!queue.isEmpty()) { int len = queue.size(); for (int i = 0; i < len; i++) { AVLTreeNode peek = queue.poll(); System.out.print("[" + peek.val + "," + peek.h + "], "); if (peek.left != nil) queue.offer(peek.left); if (peek.right != nil) queue.offer(peek.right); } } System.out.println(); }
private void inOrderTraverse(AVLTreeNode root) { if (root != nil) { inOrderTraverse(root.left); System.out.print(root.val + ", "); inOrderTraverse(root.right); } }
public static void main(String[] args) { long start = System.currentTimeMillis();
Random random = new Random();
int TIMES = 10;
while (--TIMES > 0) { System.out.println("剩余测试次数: " + TIMES); AVLTree1 avlTree2 = new AVLTree1();
int N = 1000; int M = N / 2;
Set<Integer> set = new HashSet<Integer>(); for (int i = 0; i < N; i++) { set.add(random.nextInt()); }
List<Integer> list = new ArrayList<Integer>(set); Collections.shuffle(list, random); for (int i : list) { avlTree2.insert(i); }
Collections.shuffle(list, random);
for (int i = 0; i < M; i++) { set.remove(list.get(i)); avlTree2.delete(list.get(i)); }
for (int i = 0; i < M; i++) { int k = random.nextInt(); set.add(k); avlTree2.insert(k); } list.clear(); list.addAll(set); Collections.shuffle(list, random);
for (int i : list) { avlTree2.delete(i); } } long end = System.currentTimeMillis(); System.out.println("Run time: " + (end - start) / 1000 + "s"); } }
|
5.3 版本2
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 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
| package org.liuyehcf.algorithm.datastructure.tree.avltree;
import java.util.*;
public class AVLTree2 { private AVLTreeNode root;
private AVLTreeNode nil; private Map<AVLTreeNode, Integer> highMap;
public AVLTree2() { nil = new AVLTreeNode(0); nil.left = nil; nil.right = nil; nil.parent = nil; root = nil; }
public void insert(int val) { AVLTreeNode x = root; AVLTreeNode y = nil; AVLTreeNode z = new AVLTreeNode(val); while (x != nil) { y = x; if (val < x.val) { x = x.left; } else { x = x.right; } } z.parent = y; if (y == nil) { root = z; } else if (z.val < y.val) { y.left = z; } else { y.right = z; } z.left = nil; z.right = nil; balanceFix(z); if (!check()) throw new RuntimeException(); }
private void balanceFix(AVLTreeNode z) { int originHigh = z.h;
updateHigh(z);
AVLTreeNode r = z;
if (z.left.h == z.right.h + 2) { if (z.left.left.h >= z.left.right.h) { r = rightRotate(z); } else if (z.left.left.h < z.left.right.h) { leftRotate(z.left); r = rightRotate(z); }
} else if (z.right.h == z.left.h + 2) { if (z.right.right.h >= z.right.left.h) { r = leftRotate(z); } else if (z.right.right.h < z.right.left.h) { rightRotate(z.right); r = leftRotate(z); } }
if (r.h != originHigh && r != root) balanceFix(r.parent); }
private void updateHigh(AVLTreeNode z) { z.h = Math.max(z.left.h, z.right.h) + 1; }
private AVLTreeNode leftRotate(AVLTreeNode x) { AVLTreeNode y = x.right; x.right = y.left; if (y.left != nil) { y.left.parent = x; } y.parent = x.parent; if (x.parent == nil) { root = y; } else if (x == x.parent.left) { x.parent.left = y; } else { x.parent.right = y; } y.left = x; x.parent = y;
updateHigh(x); updateHigh(y); return y; }
private AVLTreeNode rightRotate(AVLTreeNode y) { AVLTreeNode x = y.left; y.left = x.right; if (x.right != nil) { x.right.parent = y; } x.parent = y.parent; if (y.parent == nil) { root = x; } else if (y == y.parent.left) { y.parent.left = x; } else { y.parent.right = x; } x.right = y; y.parent = x;
updateHigh(y); updateHigh(x); return x; }
private boolean check() { highMap = new HashMap<AVLTreeNode, Integer>(); return checkHigh(root) && checkBalance(root); }
private boolean checkHigh(AVLTreeNode root) { if (root == nil) return true; return checkHigh(root.left) && checkHigh(root.right) && root.h == high(root); }
private int high(AVLTreeNode root) { if (root == nil) { return 0; } if (highMap.containsKey(root)) return highMap.get(root); int leftHigh = high(root.left); int rightHigh = high(root.right); highMap.put(root, Math.max(leftHigh, rightHigh) + 1); return highMap.get(root); }
private boolean checkBalance(AVLTreeNode root) { if (root == nil) { return true; } int leftHigh = root.left.h; int rightHigh = root.right.h; if (Math.abs(leftHigh - rightHigh) == 2) return false; return checkBalance(root.left) && checkBalance(root.right); }
public boolean search(int val) { return search(root, val) != nil; }
private AVLTreeNode search(AVLTreeNode x, int val) { while (x != nil) { if (x.val == val) return x; else if (val < x.val) { x = x.left; } else { x = x.right; } } return nil; }
public void delete(int val) { AVLTreeNode z = search(root, val); if (z == nil) { throw new RuntimeException(); } AVLTreeNode y = z; AVLTreeNode p = y.parent; if (z.left == nil) { transplant(z, z.right); } else if (z.right == nil) { transplant(z, z.left); } else { y = min(z.right); if (y == z.right) { p = y; } else { p = y.parent; } transplant(y, y.right);
y.right = z.right; y.right.parent = y;
y.left = z.left; y.left.parent = y;
transplant(z, y); y.h = z.h; } if (p != nil) balanceFix(p); if (!check()) throw new RuntimeException(); }
private void transplant(AVLTreeNode u, AVLTreeNode v) { v.parent = u.parent; if (u.parent == nil) { root = v; } else if (u == u.parent.left) { u.parent.left = v; } else { u.parent.right = v; } }
private AVLTreeNode min(AVLTreeNode x) { while (x.left != nil) { x = x.left; } return x; }
public void inOrderTraverse() { inOrderTraverse(root); System.out.println(); }
public void levelOrderTraversal() { Queue<AVLTreeNode> queue = new LinkedList<AVLTreeNode>(); queue.offer(root); while (!queue.isEmpty()) { int len = queue.size(); for (int i = 0; i < len; i++) { AVLTreeNode peek = queue.poll(); System.out.print("[" + peek.val + "," + peek.h + "], "); if (peek.left != nil) queue.offer(peek.left); if (peek.right != nil) queue.offer(peek.right); } } System.out.println(); }
private void inOrderTraverse(AVLTreeNode root) { if (root != nil) { inOrderTraverse(root.left); System.out.print(root.val + ", "); inOrderTraverse(root.right); } }
public static void main(String[] args) { long start = System.currentTimeMillis();
Random random = new Random();
int TIMES = 10;
while (--TIMES > 0) { System.out.println("剩余测试次数: " + TIMES); AVLTree2 avlTree = new AVLTree2();
int N = 10000; int M = N / 2;
List<Integer> list = new ArrayList<Integer>(); for (int i = 0; i < N; i++) { list.add(random.nextInt()); }
Collections.shuffle(list, random); for (int i : list) { avlTree.insert(i); }
Collections.shuffle(list, random);
for (int i = 0; i < M; i++) { int k = list.get(list.size() - 1); list.remove(list.size() - 1); avlTree.delete(k); }
for (int i = 0; i < M; i++) { int k = random.nextInt(); list.add(k); avlTree.insert(k); } Collections.shuffle(list, random);
for (int i : list) { avlTree.delete(i); } } long end = System.currentTimeMillis(); System.out.println("Run time: " + (end - start) / 1000 + "s"); } }
|