恐怖的AVL树
Posted TQCAI
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了恐怖的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 C++AVL树的实现--详细解析旋转细节