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的插入操作可以分为两个步骤:

  1. 同普通二叉查找树一样插入新值,先寻找它的正确位置,然后把包含这个新值的节点实际插入进去,新节点总是叶节点。
  2. 从这个插入节点沿双亲链返回,沿途纠正每个节点的平衡因子。如果有不平衡节点,那么在此停止,称这个节点为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树的删除可以大致分为两个阶段:

  1. 同普通二叉查找树,根据三种情况删除节点。(不清楚的同学可以看上篇博客)
  2. 从删除节点的双亲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 }

 

posted @ 2017-12-04 21:35  年华似水丶我如风  阅读(328)  评论(0编辑  收藏  举报