• 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 }
  • 相关阅读:
    CSS选择符详解之关系选择符篇
    linux基础命令入门
    asp.net 大数据导出execl实现分开压缩并下载
    一个页面从输入 URL 到页面加载显示完成,这个过程中都发生了什么?
    Git学习笔记
    ssalesforce IoT
    根据生日自动计算年龄
    Salesforce简单练习案例
    JavaScript对象
    JavaScript函数
  • 原文地址:https://www.cnblogs.com/ustcwx/p/7978549.html
Copyright © 2020-2023  润新知