• 恐怖的AVL树


    学习参考:http://www.cnblogs.com/Camilo/p/3917041.html

    今天闲来无事打算学习AVL树,并以AVL树的插入作为切入点。

    不知不觉,我就在电脑前编了4个小时……不知道是Java的引用有问题,还有C的指针也有同样的操作。比如node是递归函数中操作的一个结点,但是node是null,是他的父对象所指的。如果对node进行了赋值,但是node的父对象所指的还是null。

    这个问题很复杂,从始至终都反映在我的代码中。

    下面贴出调试了N遍的插入代码:

     1     //                  当前节点           父节点               
     2     void AVLinsert(BTNode node,BTNode parent,boolean isLeft,String data){
     3         int dataV=Integer.valueOf(data).intValue();
     4         int nodeV=0;
     5         if(node!=null) nodeV=Integer.valueOf(node.data).intValue();
     6         if(node==null){
     7             BTNode newNode=new BTNode();
     8             newNode.data=data;
     9             if(isLeft) parent.lChild=newNode;
    10             else        parent.rChild=newNode;
    11         }
    12         
    13         else if(dataV<nodeV){//向左插入
    14             AVLinsert(node.lChild,node,true,data);
    15             node.height=Math.max(getHeight(node.lChild), getHeight(node.rChild))+1;//递归增加树的高度
    16             
    17             System.out.println("sub="+(getHeight(node.lChild)-getHeight(node.rChild)));
    18             System.out.println("node="+node.data);
    19             
    20             if(getHeight(node.lChild)-getHeight(node.rChild)==2){
    21                 System.out.println("L变形前
    "+this);
    22                 if(getHeight(node.lChild.lChild)>getHeight(node.lChild.rChild)){
    23                     System.out.println("LL");
    24                     boolean flag=false;
    25                     if(root.data.equals(node.data)) flag=true;
    26                     if(!flag){
    27                         if(isLeft) parent.lChild=LLRotate(node);
    28                         else parent.rChild=LLRotate(node);
    29                     }else node=LLRotate(node);
    30                     if(flag) root=node;
    31                 }else{
    32                     System.out.println("LR");
    33                     boolean flag=false;
    34                     if(root.data.equals(node.data)) flag=true;
    35                     if(!flag){
    36                         if(isLeft) parent.lChild=LRRotate(node);
    37                         else parent.rChild=LRRotate(node);
    38                     }else node=LRRotate(node);
    39                     if(flag) root=node;
    40                 }
    41                 System.out.println("变形后
    "+this);
    42             }
    43             System.out.println(this);
    44             
    45         }else{
    46             AVLinsert(node.rChild,node,false,data);
    47             node.height=Math.max(getHeight(node.lChild), getHeight(node.rChild))+1;//递归增加树的高度
    48             
    49             System.out.println("sub="+(getHeight(node.lChild)-getHeight(node.rChild)));
    50             System.out.println("node="+node.data);
    51             
    52             if(getHeight(node.lChild)-getHeight(node.rChild)==-2){
    53                 System.out.println("R变形前
    "+this);
    54                 if(getHeight(node.rChild.lChild)>getHeight(node.rChild.rChild)){
    55                     System.out.println("RL");
    56                     boolean flag=false;
    57                     if(root.data.equals(node.data)) flag=true;
    58                     if(!flag){
    59                         if(isLeft) parent.lChild=RLRotate(node);
    60                         else parent.rChild=RLRotate(node);
    61                     }else node=RLRotate(node);
    62                     if(flag) root=node;
    63                 }else{
    64                     System.out.println("RR");
    65                     boolean flag=false;
    66                     if(root.data.equals(node.data)) flag=true;
    67                     if(!flag){
    68                         if(isLeft) parent.lChild=RRRotate(node);
    69                         else parent.rChild=RRRotate(node);
    70                     }else node=RRRotate(node);
    71                     if(flag) root=node;
    72                 }
    73                 System.out.println("变形后
    "+this);
    74             }
    75             System.out.println(this);
    76         }
    77     }

    可以看出我都要炸了。写的很乱,但是能跑起来了,以后再优化。

    AVL树平衡旋转函数:

        BTNode LLRotate(BTNode node){//左子树.高度-右子树.高度==2 【向右旋转】
            /*
             * 根节点的左孩子  为新的根节点。
             * 老根节点成为新根节点的右孩子
             * 根节点的左孩子  的右子树作为 老根节点的左子树
            */ 
            BTNode pre=node;
            node=node.lChild;//根节点的左孩子  为新的根节点。
            //从此之后node就是【根节点的左孩子】
            pre.lChild=node.rChild;//根节点的左孩子(node)  的右子树作为 老根节点(pre)的左子树
            node.rChild=pre;
            //pre: 老根节点
            pre.height=Math.max(getHeight(pre.lChild), getHeight(pre.rChild))+1;//递归增加树的高度
            node.height=Math.max(getHeight(node.lChild), getHeight(node.rChild))+1;//递归增加树的高度
            return node;//返回根节点
        }
        
        BTNode RRRotate(BTNode node){//左子树.高度-右子树.高度==-2 【向左旋转】
            /*
             * 根节点的左孩子  为新的根节点。
             * 老根节点成为新根节点的右孩子
             * 根节点的左孩子  的右子树作为 老根节点的左子树
             */    
            BTNode pre=node;
            node=node.rChild;//根节点的右孩子  为新的根节点。
            //从此之后node就是【根节点的左孩子】
            pre.rChild=node.lChild;//根节点的左孩子(node)  的右子树作为 老根节点(pre)的左子树
            node.lChild=pre;
            //pre: 老根节点
            pre.height=Math.max(getHeight(pre.lChild), getHeight(pre.rChild))+1;//递归增加树的高度
            node.height=Math.max(getHeight(node.lChild), getHeight(node.rChild))+1;//递归增加树的高度
            return node;
        }
        
        BTNode LRRotate(BTNode node){//左子树.高度-右子树.高度==2 【向右旋转】
            node.lChild=RRRotate(node.lChild);
            node=LLRotate(node);
            return node;
        }
        
        BTNode RLRotate(BTNode node){//左子树.高度-右子树.高度==2 【向右旋转】
            node.rChild=LLRotate(node.rChild);
            node=RRRotate(node);
            return node;
        }
    
        int getHeight(BTNode node){
            if(node!=null){
                return node.height;
            }else{
                return 0;
            }
        }

    完整代码:

      1 import java.util.*;
      2 
      3 public class demo {
      4     public static void main(String args[]){
      5         BTtree tree=new BTtree(3);
      6         tree.InOrderTraversal();
      7         System.out.print(tree);
      8         BThrTree thrTree=new BThrTree(tree);
      9         thrTree.InOrderTraversal();
     10         thrTree.InThreadingFabric();
     11         thrTree.InOrderTraversal_Thr();
     12         int []nums={45,12,53,3,37,24,100,61,90,78};
     13         AVLTree avl=new AVLTree(nums);
     14         avl.test();
     15     //    System.out.println(avl);
     16     //    System.out.println(avl.root.height);
     17     //    thrTree.InOrderTraversal_Thr();
     18     }
     19 }
     20 
     21 class BTtree{//二叉树类
     22     class BTNode{//节点类
     23         String data=new String("0");
     24         BTNode lChild=null;
     25         BTNode rChild=null;
     26         boolean LTag=false;//=0 : 指向左孩子。 =1 : 指向前驱
     27         boolean RTag=false;//=0 : 指向右孩子。 =1 : 指向后继
     28         int height=1;        //用于AVL树
     29         BTNode(){}
     30         BTNode(String data){this.data=data;}
     31         BTNode(int num){this.data=Integer.toString(num);};
     32     }
     33     protected BTNode root=new BTNode();
     34     BTtree(){
     35     }
     36     BTtree(int layer){
     37         //用队列的方式构造n层树
     38         List<BTNode> queue=new ArrayList<BTNode>();
     39         int front=0;
     40         int rear=0;//队尾插入
     41         queue.add(root);//初始化入队
     42         rear++;
     43         int i , k=0 , j;
     44         for(j=0;j<layer;j++){
     45             int nowRear=rear;
     46             for(i=front;i<nowRear;i++){
     47                 //出队,生两个孩子
     48                 BTNode parent=queue.get(front++);
     49                 BTNode lChild=new BTNode();
     50                 lChild.data=Integer.toString(++k);
     51                 BTNode rChild=new BTNode();
     52                 rChild.data=Integer.toString(++k);
     53                 parent.lChild=lChild;
     54                 parent.rChild=rChild;
     55                 queue.add(lChild);
     56                 rear++;
     57                 queue.add(rChild);
     58                 rear++;
     59             }
     60         }
     61     }
     62     BTtree(String express){//通过中缀表达式进行构造
     63         //1.对表达式进行括号补全。
     64         
     65         
     66     }
     67     public String toString(){//重写打印函数
     68         List<BTNode> queue=new ArrayList<BTNode>();
     69         List<String[]> PrintList=new ArrayList<String[]>();
     70         int front=0;
     71         int rear=0;//队尾插入
     72         queue.add(root);//初始化入队
     73         rear++;
     74         int i , k=0 , j;
     75         
     76         String emptySignal=new String("");//空信号
     77         
     78         String str[]=new String[1];
     79         str[0]=root.data;
     80         PrintList.add(str);//打印数据结构初始化
     81         int layer=1;//下一层字符串的数目是2^1=2。
     82         int pos=0;
     83         
     84         boolean flag=true;
     85         ok:
     86         while(flag){
     87             pos=0;//pos初始化
     88             String tmp[]=new String[(int)Math.pow((int)2, (int)(layer++))];//length=2^layer
     89             flag=false;        //循环标志初始化
     90             int nowRear=rear;
     91             int nowFront=front;
     92             for(i=front;i<nowRear;i++){
     93                 String nowStr=new String();
     94                 BTNode parent=queue.get(front++);
     95                 if(parent==null) break ok;    //跳出两重循环
     96                 if(parent.data.equals(emptySignal)){//如果是空的,派生出两个空孩子
     97                     for(int t=0;t<2;t++){
     98                         tmp[pos++]="*";
     99                         BTNode empty=new BTNode();
    100                         empty.data=emptySignal;
    101                         queue.add(empty);rear++;
    102                     }
    103                 }else{
    104                     if(parent.lChild!=null){
    105                         flag=true;                    //只要这一层存在孩子,就可以继续循环下去。
    106                         queue.add(parent.lChild);
    107                         tmp[pos++]=parent.lChild.data;
    108                         rear++;
    109                     }else{
    110                         tmp[pos++]="*";
    111                         BTNode empty=new BTNode();
    112                         empty.data=emptySignal;
    113                         queue.add(empty);
    114                         rear++;
    115                     }
    116                     if(parent.rChild!=null){
    117                         flag=true;
    118                         queue.add(parent.rChild);
    119                         tmp[pos++]=parent.rChild.data;
    120                         rear++;
    121                     }else{
    122                         tmp[pos++]="*";
    123                         BTNode empty=new BTNode();
    124                         empty.data=emptySignal;
    125                         queue.add(empty);
    126                         rear++;
    127                     }
    128                 }
    129             }                // end of for
    130             PrintList.add(tmp);
    131         }                    // end of while
    132         /*
    133         for(i=0;i<PrintList.size();i++){
    134             for(j=0;j<PrintList.get(i).length;j++) System.out.print(PrintList.get(i)[j]+" ");
    135             System.out.println();
    136         }*/
    137         //后处理
    138         String[] PrintListLine=new String[PrintList.size()-1];
    139         for(i=PrintListLine.length-1;i>=0;i--){//循环构造
    140             //首先进行构造
    141             String tmp=new String();
    142             for(j=0;j<PrintList.get(i).length;j++){
    143                 tmp+=PrintList.get(i)[j];
    144                 if(j!=PrintList.get(i).length-1) tmp+=" ";
    145             }
    146             PrintListLine[i]=tmp;
    147         }
    148         for(i=PrintListLine.length-2;i>=0;i--){//居中操作
    149             int spaceNum=(PrintListLine[i+1].length()-PrintListLine[i].length())/2;
    150             String space=new String();
    151             for(int t=0;t<spaceNum;t++) space+=" ";
    152             PrintListLine[i]=space+PrintListLine[i]+space;
    153         }    
    154         String outStr=new String();
    155         for(i=0;i<PrintListLine.length;i++){//最后构造一个字符串
    156             outStr+=PrintListLine[i]+"
    ";
    157         }
    158         return outStr;
    159     }
    160     void PreOrderTraversal(){
    161         PreOrder(root);
    162         System.out.println();
    163     }
    164     void PreOrder(BTNode obj){
    165         if(obj!=null){
    166             System.out.print(obj.data+",");
    167             PreOrder(obj.lChild);
    168             PreOrder(obj.rChild);
    169         }
    170     }
    171     void InOrderTraversal(){
    172         InOrder(root);
    173         System.out.println();
    174     }
    175     void InOrder(BTNode obj){    
    176         if(obj!=null){
    177             InOrder(obj.lChild);
    178             System.out.print(obj.data+",");
    179             InOrder(obj.rChild);
    180         }
    181     }
    182 }
    183 
    184 
    185 
    186 //线索二叉树
    187 class BThrTree extends BTtree{
    188     BThrTree(BTtree obj){//由父类构造而来
    189         //首先拷贝根节点
    190         BTNode tmp=new BTNode();
    191         tmp.data=obj.root.data;
    192         copy(root,obj.root);
    193     }
    194     void copy(BTNode node1,BTNode node2){
    195         if(node2.lChild!=null){//左树递归
    196             BTNode l=new BTNode();
    197             l.data=node2.lChild.data;//拷贝左树    
    198             node1.lChild=l;//左树赋值            
    199             copy(node1.lChild,node2.lChild);
    200         }
    201         if(node2.rChild!=null){//右树递归
    202             BTNode r=new BTNode();
    203             r.data=node2.rChild.data;//拷贝右树
    204             node1.rChild=r;//右树赋值
    205             copy(node1.rChild,node2.rChild);
    206         }    
    207     }
    208     public void InThreadingFabric(){//中序线索化构造
    209         BTNode now=root;
    210         InThreading(now); 
    211         pre.RTag=true;//【最后一个后继为null】
    212         pre.rChild=null;
    213     }
    214     private BTNode pre=null;//前驱指针
    215     private void InThreading(BTNode node){//中序线索化递归
    216         if(node!=null){//保证节点非空
    217             InThreading(node.lChild);//左子树线索化
    218             if(node.lChild==null){//如果左子树不存在
    219                 node.LTag=true;//线索化
    220                 node.lChild=pre;//前驱    【第一个前驱为null】
    221             }
    222             if(pre!=null && pre.rChild==null){//后继
    223                 pre.RTag=true;
    224                 pre.rChild=node;
    225             }
    226             pre=node;//保持pre指向node的前驱。
    227             InThreading(node.rChild);//左子树线索化
    228         }
    229     }
    230     void InOrderTraversal_Thr(){//线索化遍历
    231         BTNode now=root;
    232         //遍历前驱
    233         while(now.lChild!=null){//要么有左子树。
    234             now=now.lChild;
    235         }
    236         while(now!=null){//要么有左子树。
    237             System.out.print(now.data+",");
    238             if(now.RTag){now=now.rChild;}//如果是后继,就继续后继。
    239             else{
    240                 now=now.rChild;//如果不是,则令右子树的最左节点为后继
    241                 while(!now.LTag) now=now.lChild;
    242             }
    243         }
    244         System.out.println();
    245     }
    246 }
    247 
    248 
    249 class SearchBST extends BTtree{//二叉查找树
    250     SearchBST(int[] nums){//由二维数组构造
    251         root.data=String.valueOf(nums[0]);//构造根节点
    252         for(int i=1;i<nums.length;i++){//对其他元素进行构造
    253             BTNode node=new BTNode();
    254             node.data=String.valueOf(nums[i]);//构造叶子节点
    255             BTNode parent=root;
    256             int nodeV=nums[i];
    257             while(parent!=null){
    258                 int parentV=Integer.valueOf(parent.data).intValue();//当前根节点的值
    259                 if(nodeV<parentV){//左叶子
    260                     if(parent.lChild==null){//当前根节点的左叶子非空
    261                         parent.lChild=node;//挂入节点
    262                         break;                //如果这里没有加【break】,就会死循环。待解决☆☆☆
    263                     }
    264                     parent=parent.lChild;//如果这里空了,跳出循环
    265                 }else{
    266                     if(parent.rChild==null){
    267                         parent.rChild=node;//挂入节点
    268                         break;                //☆☆☆
    269                     }
    270                     parent=parent.rChild;//如果这里空了,跳出循环                    
    271                 }
    272             }
    273         }
    274     }
    275     SearchBST(){}
    276 }
    277 
    278 class AVLTree extends BTtree{    //平衡二叉树
    279     AVLTree(int[] nums){//由二维数组构造
    280         root.data=String.valueOf(nums[0]);
    281         for(int i=1;i<nums.length;i++) AVLinsert(root,null,true,String.valueOf(nums[i]));
    282     }
    283     BTNode LLRotate(BTNode node){//左子树.高度-右子树.高度==2 【向右旋转】
    284         /*
    285          * 根节点的左孩子  为新的根节点。
    286          * 老根节点成为新根节点的右孩子
    287          * 根节点的左孩子  的右子树作为 老根节点的左子树
    288         */ 
    289         BTNode pre=node;
    290         node=node.lChild;//根节点的左孩子  为新的根节点。
    291         //从此之后node就是【根节点的左孩子】
    292         pre.lChild=node.rChild;//根节点的左孩子(node)  的右子树作为 老根节点(pre)的左子树
    293         node.rChild=pre;
    294         //pre: 老根节点
    295         pre.height=Math.max(getHeight(pre.lChild), getHeight(pre.rChild))+1;//递归增加树的高度
    296         node.height=Math.max(getHeight(node.lChild), getHeight(node.rChild))+1;//递归增加树的高度
    297         return node;//返回根节点
    298     }
    299     
    300     BTNode RRRotate(BTNode node){//左子树.高度-右子树.高度==-2 【向左旋转】
    301         /*
    302          * 根节点的左孩子  为新的根节点。
    303          * 老根节点成为新根节点的右孩子
    304          * 根节点的左孩子  的右子树作为 老根节点的左子树
    305          */    
    306         BTNode pre=node;
    307         node=node.rChild;//根节点的右孩子  为新的根节点。
    308         //从此之后node就是【根节点的左孩子】
    309         pre.rChild=node.lChild;//根节点的左孩子(node)  的右子树作为 老根节点(pre)的左子树
    310         node.lChild=pre;
    311         //pre: 老根节点
    312         pre.height=Math.max(getHeight(pre.lChild), getHeight(pre.rChild))+1;//递归增加树的高度
    313         node.height=Math.max(getHeight(node.lChild), getHeight(node.rChild))+1;//递归增加树的高度
    314         return node;
    315     }
    316     
    317     BTNode LRRotate(BTNode node){//左子树.高度-右子树.高度==2 【向右旋转】
    318         node.lChild=RRRotate(node.lChild);
    319         node=LLRotate(node);
    320         return node;
    321     }
    322     
    323     BTNode RLRotate(BTNode node){//左子树.高度-右子树.高度==2 【向右旋转】
    324         node.rChild=LLRotate(node.rChild);
    325         node=RRRotate(node);
    326         return node;
    327     }
    328     //                  当前节点           父节点               
    329     void AVLinsert(BTNode node,BTNode parent,boolean isLeft,String data){
    330         int dataV=Integer.valueOf(data).intValue();
    331         int nodeV=0;
    332         if(node!=null) nodeV=Integer.valueOf(node.data).intValue();
    333         if(node==null){
    334             BTNode newNode=new BTNode();
    335             newNode.data=data;
    336             if(isLeft) parent.lChild=newNode;
    337             else        parent.rChild=newNode;
    338         }
    339         
    340         else if(dataV<nodeV){//向左插入
    341             AVLinsert(node.lChild,node,true,data);
    342             node.height=Math.max(getHeight(node.lChild), getHeight(node.rChild))+1;//递归增加树的高度
    343             
    344             System.out.println("sub="+(getHeight(node.lChild)-getHeight(node.rChild)));
    345             System.out.println("node="+node.data);
    346             
    347             if(getHeight(node.lChild)-getHeight(node.rChild)==2){
    348                 System.out.println("L变形前
    "+this);
    349                 if(getHeight(node.lChild.lChild)>getHeight(node.lChild.rChild)){
    350                     System.out.println("LL");
    351                     boolean flag=false;
    352                     if(root.data.equals(node.data)) flag=true;
    353                     if(!flag){
    354                         if(isLeft) parent.lChild=LLRotate(node);
    355                         else parent.rChild=LLRotate(node);
    356                     }else node=LLRotate(node);
    357                     if(flag) root=node;
    358                 }else{
    359                     System.out.println("LR");
    360                     boolean flag=false;
    361                     if(root.data.equals(node.data)) flag=true;
    362                     if(!flag){
    363                         if(isLeft) parent.lChild=LRRotate(node);
    364                         else parent.rChild=LRRotate(node);
    365                     }else node=LRRotate(node);
    366                     if(flag) root=node;
    367                 }
    368                 System.out.println("变形后
    "+this);
    369             }
    370             System.out.println(this);
    371             
    372         }else{
    373             AVLinsert(node.rChild,node,false,data);
    374             node.height=Math.max(getHeight(node.lChild), getHeight(node.rChild))+1;//递归增加树的高度
    375             
    376             System.out.println("sub="+(getHeight(node.lChild)-getHeight(node.rChild)));
    377             System.out.println("node="+node.data);
    378             
    379             if(getHeight(node.lChild)-getHeight(node.rChild)==-2){
    380                 System.out.println("R变形前
    "+this);
    381                 if(getHeight(node.rChild.lChild)>getHeight(node.rChild.rChild)){
    382                     System.out.println("RL");
    383                     boolean flag=false;
    384                     if(root.data.equals(node.data)) flag=true;
    385                     if(!flag){
    386                         if(isLeft) parent.lChild=RLRotate(node);
    387                         else parent.rChild=RLRotate(node);
    388                     }else node=RLRotate(node);
    389                     if(flag) root=node;
    390                 }else{
    391                     System.out.println("RR");
    392                     boolean flag=false;
    393                     if(root.data.equals(node.data)) flag=true;
    394                     if(!flag){
    395                         if(isLeft) parent.lChild=RRRotate(node);
    396                         else parent.rChild=RRRotate(node);
    397                     }else node=RRRotate(node);
    398                     if(flag) root=node;
    399                 }
    400                 System.out.println("变形后
    "+this);
    401             }
    402             System.out.println(this);
    403         }
    404     }
    405     
    406     int getHeight(BTNode node){
    407         if(node!=null){
    408             return node.height;
    409         }else{
    410             return 0;
    411         }
    412     }
    413     void test(){
    414         root=new BTNode(0);
    415         BTNode node[]=new BTNode[3];
    416         for(int i=0;i<3;i++) node[i]=new BTNode(i+1);
    417         root.lChild=node[0];
    418         root.lChild.rChild=node[1];
    419         root.lChild.lChild=node[2];
    420         System.out.println(this);
    421         root=LRRotate(root);
    422         System.out.println(this);
    423         System.out.println(root.height);
    424         System.out.println(root.lChild.height);
    425         System.out.println(root.rChild.height);
    426     }
    427     AVLTree(){}
    428 }
    View Code

    程序输入:45,12,53,3,37,24,100,61,90,78

    构造的树形结构:

  • 相关阅读:
    PyCharm不能使用Tab键进行整体向左缩进解决方法
    Python代码规范(PEP8)问题及解决
    Python学习开始
    Spring Annotation(@Autowire、@Qualifier)
    Spring自动装配
    servlet验证码
    Spring集合装配
    帐号明文传输漏洞
    java单元测试
    项目building workspace很慢,或者直接内存溢出的问题解决办法。
  • 原文地址:https://www.cnblogs.com/TQCAI/p/7631780.html
Copyright © 2020-2023  润新知