AVL树
定义:AVL树是一种二叉查找树,其中每一个节点的左子树和右子树的高度差至多等于1。
递归定义:AVL树是二叉查找树,其中根的左子树和右子树是高度最多相差1的AVL树。
定义不难理解,给出几个实例,体会一下。
为什么要让左右子树高度最多相差为1?这个问题在前节已经讨论过了,无非是希望树尽量平衡,使得查找和删除的时间复杂度控制在O(lg n)。那么,它是怎么做到让左右子树高度相差做多为1的呢?这里用到了一个东西叫平衡因子,对于一个节点,有三种可能的平衡因子:
- 等高 “—”:该节点的左子树和右子树是等高的。
- 右高 “ / ” : 该节点的右子树高度比它的左子树的高度大1。
- 左高 “ \ ” : 该节点的左子树高度比它的右子树的高度大1。
给出示例:
如果二叉查找树的每个节点都处在这三种平衡状态下,那自然满足AVL的条件。那平衡因子如何设定?这就要从AVL树的构建开始说起,只要保证构建的每一步,节点的平衡因子都为这三种状态之一,那构建的结果必然就是满足条件的AVL树。这里同样介绍AVL树的搜索、插入和删除操作。
- 搜索。因为AVL树是二叉平衡树,搜索操作不对树进行任何修改,所以搜索同二叉平衡树。
- 插入。插入操作和二叉查找树的过程部分相同,将节点插入后可能会引发失衡情况,而左右子树高度失衡的节点就叫作失衡节点。
旋转
Why? 如上图中的节点9和节点7都是失衡节点。如何调整平衡,使得节点都满足AVL的性质,使用的技术叫作旋转。
How to ensure the new trees reach the goal? 以最简单的两种旋转操作作下说明,盗两张图:
从上面可以看出来,旋转通过改变节点之间的位置,在失衡节点处,将较高的一侧子树高度至少降低1,相应的较低一侧子树高度则会增加(至少1)。这是基本的情况,还有更复杂的旋转,这在后面介绍插入和删除操作时,再进一步分析。
插入
AVL的插入操作可以分为两个步骤:
- 同普通二叉查找树一样插入新值,先寻找它的正确位置,然后把包含这个新值的节点实际插入进去,新节点总是叶节点。
- 从这个插入节点沿双亲链返回,沿途纠正每个节点的平衡因子。如果有不平衡节点,那么在此停止,称这个节点为X,在节点X调整平衡。R表示插入后X的较高子树的根。
当然,如果插入节点的父节点本来就有一个孩子,插入之后该节点高度不变,那就不会出现失衡节点。亦或者,在沿双亲链上行寻找失衡节点的过程中,某个节点插入未使得其高度发生变化,也可以停止继续上行。此处讨论的是插入操作导致树的高度发生变化的情况。
case 1 : X的平衡因子与R的平衡因子相同,也即X与R的平衡因子都是左高或者右高。所作操作:
- 旋转链接R-X
- 更新R和X的平衡因子
case 2 : X的平衡因子与R的平衡因子方向相反。换句话说,X是右高则R是左高,或者反过来。设Q为R较高子树的根。所作操作:
- 在链接Q-R上旋转,这一旋转使得节点X、Q和R的方向相同。
- 旋转链接Q-X
- 更新X、Q和R的平衡因子
情况2较1稍微复杂一点,要作两次旋转。为什么要两次旋转? 旋转的目的在于使得较高一侧的子树高度变低,如果直接旋转,那么R的较高子树就会粘贴到X上,那么这颗较高的子树高度并没有减少,并没有达到目的。所以要使得X和R的平衡因子相同再作旋转,就添加了一次旋转操作。
删除
同插入操作,AVL树的删除可以大致分为两个阶段:
- 同普通二叉查找树,根据三种情况删除节点。(不清楚的同学可以看上篇博客)
- 从删除节点的双亲P开始,沿着双亲链返回,沿途调整每个节点的平衡因子。
删除和插入实质上是类似的,都是因为节点数量的变化导致树的高度发生变化,所以要调整平衡因子,甚至需要旋转操作改变节点位置。稍微有点不同的是,插入上行的过程中,如果发现有节点高度未发生变化或者找到失衡节点进行旋转,结束后停止继续上行。而删除操作即使在失衡节点处旋转,之后可能依旧需要上行。因为旋转是使得树平衡的操作,旋转后树的高度减少了而不是增加了。删除操作引发的树高度减少的情况,旋转并不能中和它,只能在某个节点处保证满足AVL性质,节点的双亲链是否满足则不确定。给出删除算法的伪代码:
P:the parent of the delete node X shorter ← true while(P is not null and shorter is true) do PP ← parent of P rebalance at P { rebalance may set shorter to false} P ← PP endwhile
case 1 : P 的平衡因子等高
- 根据删除分别发生在P的左子树还是右子树,更改P的平衡因子为右高或左高。
当case 1 完成时,删除操作结束,不必向上返回。因为P的高度没有发生变化。
case 2 : P的平衡因子不是等高,P的较高子树因删除而变短。
- 将P的平衡因子改成等高。
这种情况不终止返回过程,完成后继续上行。因为该节点高度还是降低了,不能保证其父节点高度是否发生变化,及其平衡因子的调整。
case 3 :P的平衡因子不是等高,且P的较短子树因删除而变短。
这种情况涉及到旋转操作,而且比较复杂,可以进一步细分。
case 3.1 : R的平衡因子是等高。
- 旋转链接R-P
- 根据R是P的右孩子还是左孩子,分别设置R的平衡因子为左高或右高。
这是一种与插入旋转不同的操作,出现了R的平衡因子等高的情况。而插入操作是沿着双亲链旋转,因为插入导致高度变化,不可能出现R平衡因子既是等高又同时需要旋转的情况。
这种情况完成后终止返回过程,停止上行。
case 3.2 : R的平衡因子不是等高,且旋转方向与P的平衡因子方向相同。
- 旋转链接R-P
- 把R和P的平衡因子都设置为等高
这种情况下旋转,并不能使得节点高度不变,所以继续上行。
case 3.3 : R的平衡因子不是等高,且旋转的方向与P的平衡因子方向相反。(设Q为R较高子树的根)
- 旋转链接Q-R,按P、Q、R的顺序排列节点
- 旋转链接Q-P
- 设置Q的平衡因子为等高
- 根据删除前Q的子树的高度,设置R和P的平衡因子
这种情况,树的高度依旧减少,所以不停止上行。为什么减少,有兴趣的同学可以试着画一画,不想画的话可以往下看鄙人的总结。
好了,删除操作大概也就这么多。以上是书上写的内容,除了理解部分,理论基础大部分来源于《数据结构从应用到实现JAVA版》。
如果没有看过的同学,没准已经晕乎乎了。我刚看的时候也一样,后面觉得看懂了,准备写代码的时候发现:差得远呢,代码设计与实现,情况的归纳总结,这些细节,书上几乎都没有。还有插入和删除操作的一般化,肯定有人问了,为什么是这样,你的结论对所有情况都通用吗? 这些都要个人摸索,以下给出鄙人实践过程中的总结内容。
我的旋转
节点的平衡因子调节,比较简单,根据插入和删除操作的不同,获取上行的子树信息即可调整对应的平衡因子,此处略过讨论。
我的疑问也很简单:
- 旋转情况如何归类?
- 旋转除了节点的位置变化,还涉及节点的平衡因子的改变,如何调节平衡因子?
- 旋转操作对应的平衡因子的调节,涉及到固定的节点,还是会递归地影响下去?
当然,很可笑,这些都是我没有深入思考前的问题。如果是愿意动手的同学或者脑子特别灵光的那种,问题3应该已经有自己的答案了。没错,旋转操作本质上只涉及到3个节点的操作,也即Xparent、X、R,不用考虑子树的平衡因子。而实际上,一次旋转只需要考虑X和R的平衡因子调节就可以了,至于Xparent的调节则在上行之后再进行。调整的可能有多少种呢? (3*3)2 = 81, impossible! 别慌,这只是理论上的数字,我们需要筛选掉不可能出现的情况,并将剩余的可能合并。
插入和删除的旋转,有些情况是可以合并的。鄙人总结为3个类别:
情况 A:X和R的平衡因子相同,也即最简单的旋转。(也即之前介绍的 插入case 1 和 删除 case 3.2)
给出鄙人的实现代码,调用的方法详见本文结尾:
1 //情况A对应的旋转,根据平衡因子,旋转节点X和R,并调整平衡因子 2 private void rotateA(avlTree<T> X, avlTree<T> R) { 3 avlTree<T> parent = X.parent; 4 int XsubInfo = getSubInfo(X); 5 6 // 判断是左旋转还是右旋转 7 if (X.balanceFactor == BALANCE) 8 throw new TreeViolationException("The node " + X.getData() + " is balance state, dont need rotation!"); 9 else if (X.balanceFactor == LEFT_HIGHER) { //左旋转 10 setRelation(X, R.right, LEFT_SUB); 11 setRelation(R, X, RIGHT_SUB); 12 } else { //右旋转 13 setRelation(X, R.left, RIGHT_SUB); 14 setRelation(R, X, LEFT_SUB); 15 } 16 setRelation(parent, R, XsubInfo); 17 18 // 调整平衡因子 19 X.setBalanceFactor(BALANCE); 20 R.setBalanceFactor(BALANCE); 21 }
情况B: X和R的平衡因子不同(也即 插入case2 和 删除 case3)。
设R较高子树的根为Q,因平衡因子的调节规律不同,情况B又细分为B1、B2和B3。
B1> Q与R的平衡因子不同。
B2> R和Q的平衡因子相同。
B3> Q的平衡因子为等高。(只会在删除操作中出现)
给出B的实现代码:
1 // 针对失衡节点和高子树节点的平衡因子不同的情况B,设置的旋转,与A不同之处仅在于平衡因子的设置 2 private void rotateB(avlTree<T> X, avlTree<T> R, avlTree<T> Q) { 3 avlTree<T> parent = X.parent; 4 int XsubInfo = getSubInfo(X); 5 int RsubInfo = getSubInfo(R); 6 7 // 先作旋转操作,此处将两次旋转作一次操作 8 if(RsubInfo==LEFT_SUB){ //注意先后顺序 9 setRelation(R, Q.left, RIGHT_SUB); 10 setRelation(X, Q.right, LEFT_SUB); 11 setRelation(Q, X, RIGHT_SUB); 12 setRelation(Q, R, LEFT_SUB); 13 }else{ //右旋同理 14 setRelation(R, Q.right, LEFT_SUB); 15 setRelation(X, Q.left, RIGHT_SUB); 16 setRelation(Q, X, LEFT_SUB); 17 setRelation(Q, R, RIGHT_SUB); 18 } 19 setRelation(parent, Q, XsubInfo); 20 21 // 调整平衡因子 22 Q.setBalanceFactor(BALANCE); 23 if(Q.balanceFactor==BALANCE){ //B3 24 R.setBalanceFactor(BALANCE); 25 X.setBalanceFactor(BALANCE); 26 }else if(Q.balanceFactor==X.balanceFactor){ //B1 27 R.setBalanceFactor(BALANCE); 28 reverseBalanceFactor(X); 29 }else{ //B2 30 X.setBalanceFactor(BALANCE); 31 reverseBalanceFactor(R); 32 } 33 }
情况C : X为失衡节点,较高子树R的平衡因子为等高。(只会在删除操作中出现,也即上文的删除case1)
对应代码:
1 //针对删除引起的特殊旋转的情况C,设置的旋转 2 private void rotateC(avlTree<T> X, avlTree<T> R){ 3 avlTree<T> parent = X.parent; 4 int XsubInfo = getSubInfo(X); 5 6 // 先旋转 7 if(X.balanceFactor==BALANCE) 8 throw new TreeViolationException("The node "+X.getData()+" need not rotate!"); 9 else if(X.balanceFactor==LEFT_HIGHER){ 10 setRelation(X, R.right, LEFT_SUB); 11 setRelation(R, X, RIGHT_SUB); 12 }else{ 13 setRelation(X, R.left, RIGHT_SUB); 14 setRelation(R, X, LEFT_SUB); 15 } 16 setRelation(parent, R, XsubInfo); 17 18 //调整平衡因子 19 if(X.balanceFactor==LEFT_HIGHER) 20 R.setBalanceFactor(RIGHT_HIGHER); 21 else 22 R.setBalanceFactor(LEFT_HIGHER); 23 }
AVL最难最核心的东西应该就是上面这些了,除了刚开始的理论,后面全是个人工作,也许没有那么好,胜在一个体会吧,哈哈。
以下给出完整代码,这次连接口都是自己写的哦,绝对全网首发,O(∩_∩)O哈哈~
1 package com.structures.tree; 2 import java.util.HashMap; 3 4 import static com.structures.tree.constant.*; 5 6 /** 7 * Created by wx on 2017/11/23. 8 * Implement a kind of binary balanced tree which subtrees' height minus less than 1. 9 * Initialize with a head node. 10 */ 11 public class avlTree<T extends Comparable<T>> { 12 private T data; 13 private avlTree<T> parent; 14 private avlTree<T> left; 15 private avlTree<T> right; 16 private char balanceFactor; 17 18 19 private final static HashMap<Integer, Character> modifyMap = new HashMap<Integer, Character>(); 20 21 static { 22 modifyMap.put(LEFT_SUB, LEFT_HIGHER); 23 modifyMap.put(RIGHT_SUB, RIGHT_HIGHER); 24 } 25 26 // 设置头结点 27 public avlTree(){ 28 this.data = null; 29 parent = null; 30 left = null; 31 right = null; 32 setBalanceFactor(BALANCE); 33 } 34 35 // 私有构造器,insert操作时使用 36 private avlTree(T data){ 37 this.data = data; 38 parent = null; 39 left = null; 40 right = null; 41 setBalanceFactor(BALANCE); 42 } 43 44 //设定节点值 45 private void setData(T data){ 46 if (checkHeadNode(this)) 47 throw new TreeViolationException("The node is head node, forbid set data!"); 48 this.data = data; 49 } 50 51 //设定平衡因子 52 private void setBalanceFactor(char factor){ 53 balanceFactor = factor; 54 } 55 56 //检查节点是否为头结点 57 private static <T extends Comparable<T>> boolean checkHeadNode(avlTree<T> node){ 58 59 return node.parent==null; 60 } 61 62 //返回节点是其双亲节点的哪个分支信息 63 private static <T extends Comparable<T>> int getSubInfo(avlTree<T> node){ 64 if (checkHeadNode(node)) 65 throw new TreeViolationException("The tree node is a head node, has no parents!"); 66 avlTree<T> parent = node.parent; 67 68 if(parent.left == node) 69 return LEFT_SUB; 70 else 71 return RIGHT_SUB; 72 } 73 74 //将平衡因子反向 75 private static <T extends Comparable<T>> void reverseBalanceFactor(avlTree<T> node){ 76 if(node.balanceFactor==BALANCE) 77 throw new TreeViolationException(node.getData() + " is a balance tree"); 78 else if(node.balanceFactor==LEFT_HIGHER) 79 node.setBalanceFactor(RIGHT_HIGHER); 80 else 81 node.setBalanceFactor(LEFT_HIGHER); 82 } 83 84 //对parent和child建立父子关系 85 private static <T extends Comparable<T>> void setRelation(avlTree<T> parent, avlTree<T> child, int subInfo){ 86 if(child!=null) 87 child.parent = parent; 88 //因为头结点的存在,parent不会为null 89 if (subInfo == LEFT_SUB) 90 parent.left = child; 91 else 92 parent.right = child; 93 94 } 95 96 //获取节点较高子树 97 private static <T extends Comparable<T>> avlTree<T> getHighSubTree(avlTree<T> node){ 98 if(node==null) 99 throw new TreeViolationException("The tree node is empty!"); 100 101 switch(node.balanceFactor) { 102 case BALANCE: 103 throw new TreeViolationException("The tree node " + node.getData() + " hasn't higher tree!"); 104 case LEFT_HIGHER: 105 return node.left; 106 default: 107 return node.right; 108 } 109 } 110 111 //返回节点数据 112 public T getData(){ 113 return data; 114 } 115 116 // 返回整棵树的头结点 117 private avlTree<T> root(){ 118 avlTree<T> myRoot = this; 119 120 while(myRoot.parent!=null){ 121 myRoot = myRoot.parent; 122 } 123 return myRoot; 124 } 125 126 // 查找节点,此为用户接口,实际操作在findLocation中完成 127 public avlTree<T> search(T targetData){ 128 avlTree<T> searchResult = findLocation(targetData); 129 130 if(searchResult.data!=targetData) 131 throw new TreeViolationException("There is no "+targetData+" node in the tree!"); 132 133 return searchResult; 134 } 135 136 //查找节点实际操作函数 137 //返回查找结果,找不到则返回其需要插入的双亲节点 138 private avlTree<T> findLocation(T targetData){ 139 avlTree<T> root = this; //搜索的起点为头结点 140 avlTree<T> nextNode = root.right; 141 142 while(nextNode!=null){ 143 root = nextNode; 144 int result = root.getData().compareTo(targetData); 145 146 if (result == 0) 147 break; 148 else if (result > 0) 149 nextNode = root.left; 150 else 151 nextNode = root.right; 152 } 153 return root; 154 } 155 156 //插入节点,先插入,后调节平衡因子 157 public void insert(T insertData){ 158 avlTree<T> searchResult = findLocation(insertData); 159 avlTree<T> insertNode = new avlTree<T>(insertData); 160 161 if(checkHeadNode(searchResult)) { // 空树,只有头结点 162 setRelation(searchResult, insertNode, RIGHT_SUB); 163 searchResult.setBalanceFactor(RIGHT_HIGHER); 164 return; 165 } 166 int compareResult = searchResult.getData().compareTo(insertData); 167 168 if(compareResult==0) // 插入数值已存在 169 throw new TreeViolationException("Insert data " + insertData+ " already exists!"); 170 else { // 插入数值不存在 171 if (compareResult > 0) // 以左子树插入 172 setRelation(searchResult, insertNode, LEFT_SUB); 173 else //以右子树插入 174 setRelation(searchResult, insertNode, RIGHT_SUB); 175 176 // 调整并上行直至结束 177 avlTree<T> lastNode = insertNode; 178 avlTree<T> thisNode = searchResult; 179 int subInfo = getSubInfo(lastNode); 180 181 while(!checkHeadNode(thisNode)){ 182 if(thisNode.balanceFactor!=modifyMap.get(subInfo)){ //不旋转 183 if(thisNode.balanceFactor==BALANCE) 184 thisNode.setBalanceFactor(modifyMap.get(subInfo)); 185 else{ 186 thisNode.setBalanceFactor(BALANCE); // 高度未发生变化,停止上行 187 break; 188 } 189 }else{ //旋转 190 if(thisNode.balanceFactor==lastNode.balanceFactor) //情况A 191 rotateA(thisNode, lastNode); 192 else { //情况B 的1,2两种可能 193 avlTree<T> lastLastNode = getHighSubTree(lastNode); 194 rotateB(thisNode, lastNode, lastLastNode); 195 } 196 break; //旋转后,该节点高度不变,停止上行 197 } 198 lastNode = thisNode; 199 thisNode = thisNode.parent; 200 subInfo = getSubInfo(lastNode); 201 } 202 } 203 } 204 205 //删除节点并返回之,先进行一般二叉查找树的删除操作,之后调节平衡因子 206 public avlTree<T> delete(T deleteData){ 207 avlTree<T> searchResult = findLocation(deleteData); 208 avlTree<T> adjustNode; //为上行调整的起点 209 int subInfo = getSubInfo(searchResult); //存储删除子树分支信息 210 211 if(checkHeadNode(searchResult) || searchResult.getData().compareTo(deleteData)!=0) { // 空树和找不到删除节点情况 212 throw new TreeViolationException("Delete data " + deleteData+ " not exists!"); 213 } 214 215 // 先对其进行普通二叉查找树的删除操作 216 if(searchResult.left==null && searchResult.right==null){ //删除节点为叶子节点的情况 217 adjustNode = deleteNoChild(searchResult); 218 }else if(searchResult.left!=null && searchResult.right!=null) { //删除节点有两个孩子 219 // 等价于删除前趋节点,故重新复制subInfo 220 avlTree<T> preNode = getPreNode(searchResult); 221 subInfo = getSubInfo(preNode); 222 // 从删除节点的父节点处,上行调整平衡因子 223 adjustNode = deleteTwoChild(searchResult); 224 // 设置返回节点 225 searchResult = new avlTree<T>(deleteData); 226 }else{ //删除节点只有一个孩子 227 adjustNode = deleteOneChild(searchResult); 228 } 229 230 //调整平衡因子 231 avlTree<T> thisNode = adjustNode; 232 avlTree<T> lastNode; 233 234 while(!checkHeadNode(thisNode)){ 235 if(thisNode.balanceFactor==BALANCE) { //高度不变,调整后停止上行 236 thisNode.setBalanceFactor(modifyMap.get(-subInfo)); //这里是删除,所以取反 237 break; 238 }else if(thisNode.balanceFactor==modifyMap.get(subInfo)) //删除子树为较高子树,调整后继续上行 239 thisNode.setBalanceFactor(BALANCE); 240 else{ //删除子树为较短子树,需要旋转 241 lastNode = getHighSubTree(thisNode); 242 243 //由于删除操作会继续上行,因为旋转导致thisNode指向变换,故旋转后要修正thisNode的位置 244 if(lastNode.balanceFactor==BALANCE) { //对应情况C 245 rotateC(thisNode, lastNode); 246 thisNode = lastNode; //修正thisNode 247 } 248 else if(lastNode.balanceFactor == thisNode.balanceFactor) { //对应情况A 249 rotateA(thisNode, lastNode); 250 thisNode = lastNode; 251 } 252 else{ //对应情况B 1,2,3 所有可能 253 avlTree<T> lastLastNode = getHighSubTree(lastNode); 254 rotateB(thisNode, lastNode, lastLastNode); 255 thisNode = lastLastNode; 256 } 257 } 258 lastNode = thisNode; 259 thisNode = thisNode.parent; 260 subInfo = getSubInfo(lastNode); 261 } 262 263 return searchResult; 264 } 265 266 //删除节点没有孩子的情况,返回删除节点的父节点 267 private avlTree<T> deleteNoChild(avlTree<T> deleteNode){ 268 int subInfo = getSubInfo(deleteNode); 269 setRelation(deleteNode.parent, null, subInfo); 270 271 avlTree<T> parentNode = deleteNode.parent; 272 deleteNode.clear(); 273 274 return parentNode; 275 } 276 277 //删除节点有一个孩子的情况,返回删除节点的父节点,因为子树不需要调整平衡因子 278 private avlTree<T> deleteOneChild(avlTree<T> deleteNode){ 279 int subInfo = getSubInfo(deleteNode); 280 avlTree<T> child = getHighSubTree(deleteNode); 281 setRelation(deleteNode.parent, child, subInfo); 282 avlTree<T> parentNode = deleteNode.parent; 283 deleteNode.clear(); 284 285 return parentNode; 286 } 287 288 //删除节点有两个孩子的情况 289 //利用二叉查找树中该节点的前趋(后继)节点无左(右)子树,进行替换,然后删除其前趋(后继)节点 290 private avlTree<T> deleteTwoChild(avlTree<T> deleteNode){ 291 avlTree<T> preNode = getPreNode(deleteNode); 292 293 T originData = deleteNode.getData(); 294 deleteNode.setData(preNode.getData()); 295 preNode.setData(originData); 296 deleteNode = preNode; 297 avlTree<T> parentNode; 298 299 if(deleteNode.left==null && deleteNode.right==null) 300 parentNode = deleteNoChild(deleteNode); 301 else 302 parentNode = deleteOneChild(deleteNode); 303 304 return parentNode; 305 } 306 307 //情况A对应的旋转,根据平衡因子,旋转节点X和R,并调整平衡因子 308 private void rotateA(avlTree<T> X, avlTree<T> R) { 309 avlTree<T> parent = X.parent; 310 int XsubInfo = getSubInfo(X); 311 312 // 判断是左旋转还是右旋转 313 if (X.balanceFactor == BALANCE) 314 throw new TreeViolationException("The node " + X.getData() + " is balance state, dont need rotation!"); 315 else if (X.balanceFactor == LEFT_HIGHER) { //左旋转 316 setRelation(X, R.right, LEFT_SUB); 317 setRelation(R, X, RIGHT_SUB); 318 } else { //右旋转 319 setRelation(X, R.left, RIGHT_SUB); 320 setRelation(R, X, LEFT_SUB); 321 } 322 setRelation(parent, R, XsubInfo); 323 324 // 调整平衡因子 325 X.setBalanceFactor(BALANCE); 326 R.setBalanceFactor(BALANCE); 327 } 328 329 // 针对失衡节点和高子树节点的平衡因子不同的情况B,设置的旋转,与A不同之处仅在于平衡因子的设置 330 private void rotateB(avlTree<T> X, avlTree<T> R, avlTree<T> Q) { 331 avlTree<T> parent = X.parent; 332 int XsubInfo = getSubInfo(X); 333 int RsubInfo = getSubInfo(R); 334 335 // 先作旋转操作,此处将两次旋转作一次操作 336 if(RsubInfo==LEFT_SUB){ //注意先后顺序 337 setRelation(R, Q.left, RIGHT_SUB); 338 setRelation(X, Q.right, LEFT_SUB); 339 setRelation(Q, X, RIGHT_SUB); 340 setRelation(Q, R, LEFT_SUB); 341 }else{ //右旋同理 342 setRelation(R, Q.right, LEFT_SUB); 343 setRelation(X, Q.left, RIGHT_SUB); 344 setRelation(Q, X, LEFT_SUB); 345 setRelation(Q, R, RIGHT_SUB); 346 } 347 setRelation(parent, Q, XsubInfo); 348 349 // 调整平衡因子 350 Q.setBalanceFactor(BALANCE); 351 if(Q.balanceFactor==BALANCE){ //B3 352 R.setBalanceFactor(BALANCE); 353 X.setBalanceFactor(BALANCE); 354 }else if(Q.balanceFactor==X.balanceFactor){ //B1 355 R.setBalanceFactor(BALANCE); 356 reverseBalanceFactor(X); 357 }else{ //B2 358 X.setBalanceFactor(BALANCE); 359 reverseBalanceFactor(R); 360 } 361 } 362 363 //针对删除引起的特殊旋转的情况C,设置的旋转 364 private void rotateC(avlTree<T> X, avlTree<T> R){ 365 avlTree<T> parent = X.parent; 366 int XsubInfo = getSubInfo(X); 367 368 // 先旋转 369 if(X.balanceFactor==BALANCE) 370 throw new TreeViolationException("The node "+X.getData()+" need not rotate!"); 371 else if(X.balanceFactor==LEFT_HIGHER){ 372 setRelation(X, R.right, LEFT_SUB); 373 setRelation(R, X, RIGHT_SUB); 374 }else{ 375 setRelation(X, R.left, RIGHT_SUB); 376 setRelation(R, X, LEFT_SUB); 377 } 378 setRelation(parent, R, XsubInfo); 379 380 //调整平衡因子 381 if(X.balanceFactor==LEFT_HIGHER) 382 R.setBalanceFactor(RIGHT_HIGHER); 383 else 384 R.setBalanceFactor(LEFT_HIGHER); 385 } 386 387 //中序遍历avl树 388 public static <T extends Comparable<T>> void inOrderTraverse(avlTree<T> treeNode){ 389 if(treeNode.left!=null) { 390 inOrderTraverse(treeNode.left); 391 } 392 if(treeNode.getData()!=null) //头结点不输出 393 System.out.println(treeNode.getData() + " "+ treeNode.balanceFactor); 394 if(treeNode.right!=null){ 395 inOrderTraverse(treeNode.right); 396 } 397 } 398 399 //获取节点前趋,只针对此处节点有两个孩子的情况 400 private avlTree<T> getPreNode(avlTree<T> node){ 401 avlTree<T> preNode = node.left; 402 403 while (preNode.right!=null){ //寻找前趋节点 404 preNode = preNode.right; 405 } 406 407 return preNode; 408 } 409 410 //清空树的链接 411 private void clear(){ 412 left=null; 413 right=null; 414 parent=null; 415 setBalanceFactor(BALANCE); 416 } 417 }