恐怖的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变形前\n"+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("变形后\n"+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变形前\n"+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("变形后\n"+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]+"\n";
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变形前\n"+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("变形后\n"+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变形前\n"+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("变形后\n"+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

构造的树形结构:

 

posted @ 2017-10-06 16:59  TQCAI  阅读(196)  评论(0编辑  收藏  举报