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

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

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

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

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

     //                  当前节点           父节点
void AVLinsert(BTNode node,BTNode parent,boolean isLeft,String data){
int dataV=Integer.valueOf(data).intValue();
int nodeV=0;
if(node!=null) nodeV=Integer.valueOf(node.data).intValue();
if(node==null){
BTNode newNode=new BTNode();
newNode.data=data;
if(isLeft) parent.lChild=newNode;
else parent.rChild=newNode;
} else if(dataV<nodeV){//向左插入
AVLinsert(node.lChild,node,true,data);
node.height=Math.max(getHeight(node.lChild), getHeight(node.rChild))+1;//递归增加树的高度 System.out.println("sub="+(getHeight(node.lChild)-getHeight(node.rChild)));
System.out.println("node="+node.data); if(getHeight(node.lChild)-getHeight(node.rChild)==2){
System.out.println("L变形前\n"+this);
if(getHeight(node.lChild.lChild)>getHeight(node.lChild.rChild)){
System.out.println("LL");
boolean flag=false;
if(root.data.equals(node.data)) flag=true;
if(!flag){
if(isLeft) parent.lChild=LLRotate(node);
else parent.rChild=LLRotate(node);
}else node=LLRotate(node);
if(flag) root=node;
}else{
System.out.println("LR");
boolean flag=false;
if(root.data.equals(node.data)) flag=true;
if(!flag){
if(isLeft) parent.lChild=LRRotate(node);
else parent.rChild=LRRotate(node);
}else node=LRRotate(node);
if(flag) root=node;
}
System.out.println("变形后\n"+this);
}
System.out.println(this); }else{
AVLinsert(node.rChild,node,false,data);
node.height=Math.max(getHeight(node.lChild), getHeight(node.rChild))+1;//递归增加树的高度 System.out.println("sub="+(getHeight(node.lChild)-getHeight(node.rChild)));
System.out.println("node="+node.data); if(getHeight(node.lChild)-getHeight(node.rChild)==-2){
System.out.println("R变形前\n"+this);
if(getHeight(node.rChild.lChild)>getHeight(node.rChild.rChild)){
System.out.println("RL");
boolean flag=false;
if(root.data.equals(node.data)) flag=true;
if(!flag){
if(isLeft) parent.lChild=RLRotate(node);
else parent.rChild=RLRotate(node);
}else node=RLRotate(node);
if(flag) root=node;
}else{
System.out.println("RR");
boolean flag=false;
if(root.data.equals(node.data)) flag=true;
if(!flag){
if(isLeft) parent.lChild=RRRotate(node);
else parent.rChild=RRRotate(node);
}else node=RRRotate(node);
if(flag) root=node;
}
System.out.println("变形后\n"+this);
}
System.out.println(this);
}
}

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

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;
}
}

完整代码:

 import java.util.*;

 public class demo {
public static void main(String args[]){
BTtree tree=new BTtree(3);
tree.InOrderTraversal();
System.out.print(tree);
BThrTree thrTree=new BThrTree(tree);
thrTree.InOrderTraversal();
thrTree.InThreadingFabric();
thrTree.InOrderTraversal_Thr();
int []nums={45,12,53,3,37,24,100,61,90,78};
AVLTree avl=new AVLTree(nums);
avl.test();
// System.out.println(avl);
// System.out.println(avl.root.height);
// thrTree.InOrderTraversal_Thr();
}
} class BTtree{//二叉树类
class BTNode{//节点类
String data=new String("0");
BTNode lChild=null;
BTNode rChild=null;
boolean LTag=false;//=0 : 指向左孩子。 =1 : 指向前驱
boolean RTag=false;//=0 : 指向右孩子。 =1 : 指向后继
int height=1; //用于AVL树
BTNode(){}
BTNode(String data){this.data=data;}
BTNode(int num){this.data=Integer.toString(num);};
}
protected BTNode root=new BTNode();
BTtree(){
}
BTtree(int layer){
//用队列的方式构造n层树
List<BTNode> queue=new ArrayList<BTNode>();
int front=0;
int rear=0;//队尾插入
queue.add(root);//初始化入队
rear++;
int i , k=0 , j;
for(j=0;j<layer;j++){
int nowRear=rear;
for(i=front;i<nowRear;i++){
//出队,生两个孩子
BTNode parent=queue.get(front++);
BTNode lChild=new BTNode();
lChild.data=Integer.toString(++k);
BTNode rChild=new BTNode();
rChild.data=Integer.toString(++k);
parent.lChild=lChild;
parent.rChild=rChild;
queue.add(lChild);
rear++;
queue.add(rChild);
rear++;
}
}
}
BTtree(String express){//通过中缀表达式进行构造
//1.对表达式进行括号补全。 }
public String toString(){//重写打印函数
List<BTNode> queue=new ArrayList<BTNode>();
List<String[]> PrintList=new ArrayList<String[]>();
int front=0;
int rear=0;//队尾插入
queue.add(root);//初始化入队
rear++;
int i , k=0 , j; String emptySignal=new String("");//空信号 String str[]=new String[1];
str[0]=root.data;
PrintList.add(str);//打印数据结构初始化
int layer=1;//下一层字符串的数目是2^1=2。
int pos=0; boolean flag=true;
ok:
while(flag){
pos=0;//pos初始化
String tmp[]=new String[(int)Math.pow((int)2, (int)(layer++))];//length=2^layer
flag=false; //循环标志初始化
int nowRear=rear;
int nowFront=front;
for(i=front;i<nowRear;i++){
String nowStr=new String();
BTNode parent=queue.get(front++);
if(parent==null) break ok; //跳出两重循环
if(parent.data.equals(emptySignal)){//如果是空的,派生出两个空孩子
for(int t=0;t<2;t++){
tmp[pos++]="*";
BTNode empty=new BTNode();
empty.data=emptySignal;
queue.add(empty);rear++;
}
}else{
if(parent.lChild!=null){
flag=true; //只要这一层存在孩子,就可以继续循环下去。
queue.add(parent.lChild);
tmp[pos++]=parent.lChild.data;
rear++;
}else{
tmp[pos++]="*";
BTNode empty=new BTNode();
empty.data=emptySignal;
queue.add(empty);
rear++;
}
if(parent.rChild!=null){
flag=true;
queue.add(parent.rChild);
tmp[pos++]=parent.rChild.data;
rear++;
}else{
tmp[pos++]="*";
BTNode empty=new BTNode();
empty.data=emptySignal;
queue.add(empty);
rear++;
}
}
} // end of for
PrintList.add(tmp);
} // end of while
/*
for(i=0;i<PrintList.size();i++){
for(j=0;j<PrintList.get(i).length;j++) System.out.print(PrintList.get(i)[j]+" ");
System.out.println();
}*/
//后处理
String[] PrintListLine=new String[PrintList.size()-1];
for(i=PrintListLine.length-1;i>=0;i--){//循环构造
//首先进行构造
String tmp=new String();
for(j=0;j<PrintList.get(i).length;j++){
tmp+=PrintList.get(i)[j];
if(j!=PrintList.get(i).length-1) tmp+=" ";
}
PrintListLine[i]=tmp;
}
for(i=PrintListLine.length-2;i>=0;i--){//居中操作
int spaceNum=(PrintListLine[i+1].length()-PrintListLine[i].length())/2;
String space=new String();
for(int t=0;t<spaceNum;t++) space+=" ";
PrintListLine[i]=space+PrintListLine[i]+space;
}
String outStr=new String();
for(i=0;i<PrintListLine.length;i++){//最后构造一个字符串
outStr+=PrintListLine[i]+"\n";
}
return outStr;
}
void PreOrderTraversal(){
PreOrder(root);
System.out.println();
}
void PreOrder(BTNode obj){
if(obj!=null){
System.out.print(obj.data+",");
PreOrder(obj.lChild);
PreOrder(obj.rChild);
}
}
void InOrderTraversal(){
InOrder(root);
System.out.println();
}
void InOrder(BTNode obj){
if(obj!=null){
InOrder(obj.lChild);
System.out.print(obj.data+",");
InOrder(obj.rChild);
}
}
} //线索二叉树
class BThrTree extends BTtree{
BThrTree(BTtree obj){//由父类构造而来
//首先拷贝根节点
BTNode tmp=new BTNode();
tmp.data=obj.root.data;
copy(root,obj.root);
}
void copy(BTNode node1,BTNode node2){
if(node2.lChild!=null){//左树递归
BTNode l=new BTNode();
l.data=node2.lChild.data;//拷贝左树
node1.lChild=l;//左树赋值
copy(node1.lChild,node2.lChild);
}
if(node2.rChild!=null){//右树递归
BTNode r=new BTNode();
r.data=node2.rChild.data;//拷贝右树
node1.rChild=r;//右树赋值
copy(node1.rChild,node2.rChild);
}
}
public void InThreadingFabric(){//中序线索化构造
BTNode now=root;
InThreading(now);
pre.RTag=true;//【最后一个后继为null】
pre.rChild=null;
}
private BTNode pre=null;//前驱指针
private void InThreading(BTNode node){//中序线索化递归
if(node!=null){//保证节点非空
InThreading(node.lChild);//左子树线索化
if(node.lChild==null){//如果左子树不存在
node.LTag=true;//线索化
node.lChild=pre;//前驱 【第一个前驱为null】
}
if(pre!=null && pre.rChild==null){//后继
pre.RTag=true;
pre.rChild=node;
}
pre=node;//保持pre指向node的前驱。
InThreading(node.rChild);//左子树线索化
}
}
void InOrderTraversal_Thr(){//线索化遍历
BTNode now=root;
//遍历前驱
while(now.lChild!=null){//要么有左子树。
now=now.lChild;
}
while(now!=null){//要么有左子树。
System.out.print(now.data+",");
if(now.RTag){now=now.rChild;}//如果是后继,就继续后继。
else{
now=now.rChild;//如果不是,则令右子树的最左节点为后继
while(!now.LTag) now=now.lChild;
}
}
System.out.println();
}
} class SearchBST extends BTtree{//二叉查找树
SearchBST(int[] nums){//由二维数组构造
root.data=String.valueOf(nums[0]);//构造根节点
for(int i=1;i<nums.length;i++){//对其他元素进行构造
BTNode node=new BTNode();
node.data=String.valueOf(nums[i]);//构造叶子节点
BTNode parent=root;
int nodeV=nums[i];
while(parent!=null){
int parentV=Integer.valueOf(parent.data).intValue();//当前根节点的值
if(nodeV<parentV){//左叶子
if(parent.lChild==null){//当前根节点的左叶子非空
parent.lChild=node;//挂入节点
break; //如果这里没有加【break】,就会死循环。待解决☆☆☆
}
parent=parent.lChild;//如果这里空了,跳出循环
}else{
if(parent.rChild==null){
parent.rChild=node;//挂入节点
break; //☆☆☆
}
parent=parent.rChild;//如果这里空了,跳出循环
}
}
}
}
SearchBST(){}
} class AVLTree extends BTtree{ //平衡二叉树
AVLTree(int[] nums){//由二维数组构造
root.data=String.valueOf(nums[0]);
for(int i=1;i<nums.length;i++) AVLinsert(root,null,true,String.valueOf(nums[i]));
}
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;
}
// 当前节点 父节点
void AVLinsert(BTNode node,BTNode parent,boolean isLeft,String data){
int dataV=Integer.valueOf(data).intValue();
int nodeV=0;
if(node!=null) nodeV=Integer.valueOf(node.data).intValue();
if(node==null){
BTNode newNode=new BTNode();
newNode.data=data;
if(isLeft) parent.lChild=newNode;
else parent.rChild=newNode;
} else if(dataV<nodeV){//向左插入
AVLinsert(node.lChild,node,true,data);
node.height=Math.max(getHeight(node.lChild), getHeight(node.rChild))+1;//递归增加树的高度 System.out.println("sub="+(getHeight(node.lChild)-getHeight(node.rChild)));
System.out.println("node="+node.data); if(getHeight(node.lChild)-getHeight(node.rChild)==2){
System.out.println("L变形前\n"+this);
if(getHeight(node.lChild.lChild)>getHeight(node.lChild.rChild)){
System.out.println("LL");
boolean flag=false;
if(root.data.equals(node.data)) flag=true;
if(!flag){
if(isLeft) parent.lChild=LLRotate(node);
else parent.rChild=LLRotate(node);
}else node=LLRotate(node);
if(flag) root=node;
}else{
System.out.println("LR");
boolean flag=false;
if(root.data.equals(node.data)) flag=true;
if(!flag){
if(isLeft) parent.lChild=LRRotate(node);
else parent.rChild=LRRotate(node);
}else node=LRRotate(node);
if(flag) root=node;
}
System.out.println("变形后\n"+this);
}
System.out.println(this); }else{
AVLinsert(node.rChild,node,false,data);
node.height=Math.max(getHeight(node.lChild), getHeight(node.rChild))+1;//递归增加树的高度 System.out.println("sub="+(getHeight(node.lChild)-getHeight(node.rChild)));
System.out.println("node="+node.data); if(getHeight(node.lChild)-getHeight(node.rChild)==-2){
System.out.println("R变形前\n"+this);
if(getHeight(node.rChild.lChild)>getHeight(node.rChild.rChild)){
System.out.println("RL");
boolean flag=false;
if(root.data.equals(node.data)) flag=true;
if(!flag){
if(isLeft) parent.lChild=RLRotate(node);
else parent.rChild=RLRotate(node);
}else node=RLRotate(node);
if(flag) root=node;
}else{
System.out.println("RR");
boolean flag=false;
if(root.data.equals(node.data)) flag=true;
if(!flag){
if(isLeft) parent.lChild=RRRotate(node);
else parent.rChild=RRRotate(node);
}else node=RRRotate(node);
if(flag) root=node;
}
System.out.println("变形后\n"+this);
}
System.out.println(this);
}
} int getHeight(BTNode node){
if(node!=null){
return node.height;
}else{
return 0;
}
}
void test(){
root=new BTNode(0);
BTNode node[]=new BTNode[3];
for(int i=0;i<3;i++) node[i]=new BTNode(i+1);
root.lChild=node[0];
root.lChild.rChild=node[1];
root.lChild.lChild=node[2];
System.out.println(this);
root=LRRotate(root);
System.out.println(this);
System.out.println(root.height);
System.out.println(root.lChild.height);
System.out.println(root.rChild.height);
}
AVLTree(){}
}

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

构造的树形结构:

恐怖的AVL树的更多相关文章

  1. 算法与数据结构(十一) 平衡二叉树(AVL树)

    今天的博客是在上一篇博客的基础上进行的延伸.上一篇博客我们主要聊了二叉排序树,详情请戳<二叉排序树的查找.插入与删除>.本篇博客我们就在二叉排序树的基础上来聊聊平衡二叉树,也叫AVL树,A ...

  2. AVL树原理及实现(C语言实现以及Java语言实现)

    欢迎探讨,如有错误敬请指正 如需转载,请注明出处http://www.cnblogs.com/nullzx/ 1. AVL定义 AVL树是一种改进版的搜索二叉树.对于一般的搜索二叉树而言,如果数据恰好 ...

  3. AVL树

    AVL树 在二叉查找树(BST)中,频繁的插入操作可能会让树的性能发生退化,因此,需要加入一些平衡操作,使树的高度达到理想的O(logn),这就是AVL树出现的背景.注意,AVL树的起名来源于两个发明 ...

  4. AVL树的平衡算法(JAVA实现)

      1.概念: AVL树本质上还是一个二叉搜索树,不过比二叉搜索树多了一个平衡条件:每个节点的左右子树的高度差不大于1. 二叉树的应用是为了弥补链表的查询效率问题,但是极端情况下,二叉搜索树会无限接近 ...

  5. 【数据结构】平衡二叉树—AVL树

    (百度百科)在计算机科学中,AVL树是最先发明的自平衡二叉查找树.在AVL树中任何节点的两个子树的高度最大差别为一,所以它也被称为高度平衡树.查找.插入和删除在平均和最坏情况下都是O(log n).增 ...

  6. 数据结构图文解析之:AVL树详解及C++模板实现

    0. 数据结构图文解析系列 数据结构系列文章 数据结构图文解析之:数组.单链表.双链表介绍及C++模板实现 数据结构图文解析之:栈的简介及C++模板实现 数据结构图文解析之:队列详解与C++模板实现 ...

  7. 数据结构之平衡二叉树(AVL树)

    平衡二叉树(AVL树)定义如下:平衡二叉树或者是一棵空树,或者是具有以下性质的二叉排序树: (1)它的左子树和右子树的高度之差绝对值不超过1: (2)它的左子树和右子树都是平衡二叉树. AVL树避免了 ...

  8. PAT树_层序遍历叶节点、中序建树后序输出、AVL树的根、二叉树路径存在性判定、奇妙的完全二叉搜索树、最小堆路径、文件路由

    03-树1. List Leaves (25) Given a tree, you are supposed to list all the leaves in the order of top do ...

  9. 论AVL树与红黑树

    首先讲解一下AVL树: 例如,我们要输入这样一串数字,10,9,8,7,15,20这样一串数字来建立AVL树 1,首先输入10,得到一个根结点10 2,然后输入9, 得到10这个根结点一个左孩子结点9 ...

随机推荐

  1. PhpStorm注册使用方法

    解压 sudo tar -zvxf PhpStorm-2019.3.tar.gz -C /usr/local 屏蔽hosts # Phpstorm 0.0.0.0 account.jetbrains. ...

  2. postgresql NUMERIC(precision, scale)

  3. nginx 配置处理静态资源

    前言:在一些中大型的网站中,都会专门配置一个处理静态资源的服务,下面我们来用NGINX实战配置下 配置静态资源的目的是为了加速静态资源的访问速度 比较简单,下面直接上配置了 以上就是文章内容的全部了

  4. Linux 笔记 - 第二十二章 Nginx 配置 SSL

    一.前言 基础知识 1.1 公钥密码体制(public-key cryptography) 公钥密码体制分为三个部分,公钥.私钥.加密解密算法,它的加密解密过程如下: 加密:通过加密算法和公钥对内容( ...

  5. .Net Core 学习路线图

    今天看  草根专栏 这位大牛的微信公众号,上面分享了一张来自github的.net core学习路线图,贴在这里,好让自己学习有个方向,这么一大页竟然只是初级到高级的,我的个乖乖,太恐怖了. 感谢大牛 ...

  6. 10、VUE路由技术

    1.前端路由 前端路由在很多开源的js类库框架中都得到支持,如AngularJS.Backbone.Vue.js等等. 前端路由和后端路由原理一样,是让所有的交互和展示在一个页面运行,以达到减少服务器 ...

  7. AspNet Core结合Quartz使用定时任务且通过注入缓存或者配置参数

    一.经常在项目会用到定时任务同步数据或更新缓存等操作,在很久以前我们可能经常会用一个多线程或timer来做定时任务,这样能实现比较简单轻量级的任务:对于任务多且都调用频率不一样的任务,我们都会用到Qu ...

  8. Java之路---Day17(数据结构)

    2019-11-04-23:03:13 目录: 1.常用的数据结构 2.栈 3.队列 4.数组 5.链表 6.红黑树 常用的数据结构: 包含:栈.队列.数组.链表和红黑树 栈: 栈:stack,又称堆 ...

  9. 英语lasurite青金石lasurite单词

    lasurite青金石的蓝色,是希望的颜色. 医药功效:青金石可入药,是世界公认的.青金即青金石,是一种不透明或半透明的蓝色.蓝紫色或蓝绿色的准宝石,主要由天蓝石和方解石组成.青金石色是藏传佛教中药师 ...

  10. REDELK的安装和使用

    0x00 前言简介 红队的SIEM有两个主要目标: 通过创建一个集中管理中心,收集和丰富来自多个 teamservers的所有相关操作日志,增强了红队人员的可用性和概述.这对于在操作中进行历史搜索以及 ...