AVL树插入操作实现
为了提高二插排序树的性能,规定树中的每个节点的左子树和右子树高度差的绝对值不能大于1。为了满足上面的要求需要在插入完成后对树进行调整。下面介绍各个调整方式。
右单旋转
如下图所示,节点A的平衡因子(左子树高度减右子树高度)为1。由于在节点A的左孩子B的左子树上插入了新节点,导致B的左子树高度增加1,从而导致A的平衡因子为2,这时为了保持平衡需要对树进行调整。

旋转的方法就是将A的变为B的右子树,将B的右子树变为A的左子树。
示例代码:
private Node RRotate(Node node){
Node A </span>=<span style="color: #000000"> node;
Node B </span>=<span style="color: #000000"> node.LChild;
</span><span style="color: #008000">//</span><span style="color: #008000">旋转</span>
Node tmp =<span style="color: #000000"> B.RChild;
B.RChild </span>=<span style="color: #000000"> A;
A.LChild </span>=<span style="color: #000000"> tmp;
</span><span style="color: #008000">//</span><span style="color: #008000">更新树的高度</span>
A.height = Math.max(height(A.LChild), height(A.RChild))+1<span style="color: #000000">;
B.height </span>= Math.max(height(B.LChild), height(B.RChild))+1<span style="color: #000000">;
</span><span style="color: #0000ff">return</span><span style="color: #000000"> B;
}</span></pre></div>
(每个节点我们维护了一个height的属性来记录树的高度,每次旋转完成后需要更新树的高度。因为旋转会导致书的根节点发生变化,所以每次旋转完成后需要将新的根节点返回)
左单旋转
左单旋转整好与右单旋转相反。右单旋转是因为左子树太高,而左单旋转则是因为右子树太高,需要降低其高度。
如图所示节点B的右子树高度增加1,导致节点A的平衡因子变为-2,所以需要进行左旋调整位置。

旋转方法:将A变为B的左子树,将B的左子树变为A的右子树
示例代码:
private Node LRotate(Node node){
Node A = node;
Node B = node.RChild;
</span><span style="color: #008000">//</span><span style="color: #008000">旋转</span>
Node tmp =<span style="color: #000000"> B.LChild;
B.LChild </span>=<span style="color: #000000"> A;
A.RChild </span>=<span style="color: #000000"> tmp;
</span><span style="color: #008000">//</span><span style="color: #008000">更新树的高度</span>
A.height = Math.max(height(A.LChild), height(A.RChild))+1<span style="color: #000000">;
B.height </span>= Math.max(height(B.LChild), height(B.RChild))+1<span style="color: #000000">;
</span><span style="color: #0000ff">return</span><span style="color: #000000"> B;
}</span></pre></div>
(每个节点我们维护了一个height的属性来记录树的高度,每次旋转完成后需要更新树的高度。因为旋转会导致书的根节点发生变化,所以每次旋转完成后需要将新的根节点返回)
先左后右旋转
上面的两种情况处理比较简单,因为插入的节点要么是根节点左孩子的左子树或者是根节点右孩子的右子树。如果插入的节点在根节点左孩子的右子树上,则需要先进行左旋然后进行右旋操作。

如图所示,插入的节点在B节点右子树上,这时需要对B节点进行左旋操作,然后对A节点进行右旋操作。
示例代码:
private Node LRRotate(Node node){
//先进行左旋
LRotate(node.LChild);
//在进行右旋
return RRotate(node);
}
代码中node节点就是图中的A节点,先对A节点的左孩子B进行左旋操作,然后对A(node)节点进行右旋操作
先右旋后左旋
当插入的节点在根节点的右孩子的左子树上,则需要进行先右旋后左旋操作。

示例代码:
//先右后左旋转
private Node RLRotate(Node node){
//再进行右旋转
RRotate(node.RChild);
//再进行右旋
return LRotate(node);
}
插入操作
插入操作通过递归方式实现,在插入操作完成后需要对访问路径上的每个节点进行判断来确定是否要旋转。
public Node insert(Node node, int i){
//先将节点插入到树中
if(node == null)
return new Node(i, 1, node);
</span><span style="color: #008000">//</span><span style="color: #008000">插入的值与当前节点值进行比较来确定插入的位置</span>
<span style="color: #0000ff">if</span>(i <<span style="color: #000000"> node.val){
node.LChild </span>=<span style="color: #000000"> insert(node.LChild, i);
</span><span style="color: #008000">//</span><span style="color: #008000">判断是否进行调整</span>
<span style="color: #0000ff">if</span>(height(node.LChild) - height(node.RChild) == 2<span style="color: #000000">){
</span><span style="color: #0000ff">if</span>(i <<span style="color: #000000"> node.LChild.val)
</span><span style="color: #008000">//</span><span style="color: #008000">插入的节点在左孩子的左子树上,则需要进行右旋</span>
node =<span style="color: #000000"> RRotate(node);
</span><span style="color: #0000ff">else</span>
<span style="color: #008000">//</span><span style="color: #008000">插入的节点在左孩子的右子树上,则需要先进行左旋后进行右旋</span>
node =<span style="color: #000000"> LRRotate(node);
}
}
</span><span style="color: #0000ff">else</span><span style="color: #000000">{
node.RChild </span>=<span style="color: #000000"> insert(node.RChild, i);
</span><span style="color: #0000ff">if</span>(height(node.LChild) - height(node.RChild) == -2<span style="color: #000000">){
</span><span style="color: #0000ff">if</span>(i ><span style="color: #000000"> node.RChild.val)
node </span>=<span style="color: #000000"> LRotate(node);
</span><span style="color: #0000ff">else</span><span style="color: #000000">
node </span>=<span style="color: #000000"> RLRotate(node);
}
}
node.height </span>= Math.max(height(node.LChild), height(node.RChild))+1<span style="color: #000000">;
</span><span style="color: #0000ff">return</span><span style="color: #000000"> node;
}</span></pre></div>
//计算树的高度,主要解决空树高度的问题(空树的高度为0)
private int height(Node node){
return node == null ? 0:node.height;
}
判断一棵树是否是AVL树
判断时通过后续遍历的方式来比较左右子树的高度差
static boolean isBalance(Node node,Depth d){
if(node == null){
d.height=0;
return true;
}
Depth right=new Depth();
Depth left = new Depth();
if(isBalance(node.LChild,left)&&isBalance(node.RChild, right)){
if(Math.abs(left.height - right.height)<2){//绝对值小于等于1
//如果是平衡树,才有必要算深度,然后看上级是不是平衡树
d.height=(left.height>right.height?left.height:right.height)+1;
System.out.println("left="+left.height+" right="+right.height+" height"+d.height+" value="+node.val);
return true;
}
}
System.out.println("left="+left.height+" right="+right.height+" height"+d.height+" value="+node.val);
return false;
}
</span><span style="color: #0000ff">static</span> <span style="color: #0000ff">class</span><span style="color: #000000"> Depth{
</span><span style="color: #0000ff">int</span><span style="color: #000000"> height;
}</span></pre></div>
完整代码
package com.dy.xidian;
public class AVL {
private Node root;
static class Node{
int val; //存储数据
int height; //权重
Node LChild; //右孩子
Node RChild; //左孩子
<span style="color: #0000ff">public</span> Node(<span style="color: #0000ff">int</span> k, <span style="color: #0000ff">int</span><span style="color: #000000"> _height){
</span><span style="color: #0000ff">this</span>.val =<span style="color: #000000"> k;
</span><span style="color: #0000ff">this</span>. height =<span style="color: #000000"> _height;
}
}
</span><span style="color: #0000ff">private</span> <span style="color: #0000ff">void</span> initAVL(<span style="color: #0000ff">int</span><span style="color: #000000">[] arr){
</span><span style="color: #0000ff">for</span>(<span style="color: #0000ff">int</span><span style="color: #000000"> i : arr)
root </span>=<span style="color: #000000"> insert(root, i);
}
</span><span style="color: #0000ff">public</span> AVL(<span style="color: #0000ff">int</span><span style="color: #000000">[] arr){
initAVL(arr);
}
</span><span style="color: #008000">//</span><span style="color: #008000">右旋</span>
<span style="color: #0000ff">private</span><span style="color: #000000"> Node RRotate(Node node){
Node A </span>=<span style="color: #000000"> node;
Node B </span>=<span style="color: #000000"> node.LChild;
</span><span style="color: #008000">//</span><span style="color: #008000">旋转</span>
Node tmp =<span style="color: #000000"> B.RChild;
B.RChild </span>=<span style="color: #000000"> A;
A.LChild </span>=<span style="color: #000000"> tmp;
</span><span style="color: #008000">//</span><span style="color: #008000">更新树的高度</span>
A.height = Math.max(height(A.LChild), height(A.RChild))+1<span style="color: #000000">;
B.height </span>= Math.max(height(B.LChild), height(B.RChild))+1<span style="color: #000000">;
</span><span style="color: #0000ff">return</span><span style="color: #000000"> B;
}
</span><span style="color: #008000">//</span><span style="color: #008000">左旋</span>
<span style="color: #0000ff">private</span><span style="color: #000000"> Node LRotate(Node node){
Node A </span>=<span style="color: #000000"> node;
Node B </span>=<span style="color: #000000"> node.RChild;
</span><span style="color: #008000">//</span><span style="color: #008000">旋转</span>
Node tmp =<span style="color: #000000"> B.LChild;
B.LChild </span>=<span style="color: #000000"> A;
A.RChild </span>=<span style="color: #000000"> tmp;
</span><span style="color: #008000">//</span><span style="color: #008000">更新树的高度</span>
A.height = Math.max(height(A.LChild), height(A.RChild))+1<span style="color: #000000">;
B.height </span>= Math.max(height(B.LChild), height(B.RChild))+1<span style="color: #000000">;
</span><span style="color: #0000ff">return</span><span style="color: #000000"> B;
}
</span><span style="color: #008000">//</span><span style="color: #008000">先左后右旋转</span>
<span style="color: #0000ff">private</span><span style="color: #000000"> Node LRRotate(Node node){
</span><span style="color: #008000">//</span><span style="color: #008000">先进行左旋</span>
LRotate(node.LChild);
//在进行右旋
return RRotate(node);
}
</span><span style="color: #008000">//</span><span style="color: #008000">先右后左旋转</span>
<span style="color: #0000ff">private</span><span style="color: #000000"> Node RLRotate(Node node){
</span><span style="color: #008000">//</span><span style="color: #008000">再进行右旋转</span>
RRotate(node.RChild);
//再进行右旋
return LRotate(node);
}
</span><span style="color: #008000">//</span><span style="color: #008000">计算树的高度,主要解决空树高度的问题(空树的高度为0)</span>
<span style="color: #0000ff">private</span> <span style="color: #0000ff">int</span><span style="color: #000000"> height(Node node){
</span><span style="color: #0000ff">return</span> node == <span style="color: #0000ff">null</span> ? 0<span style="color: #000000">:node.height;
}
</span><span style="color: #0000ff">public</span> Node insert(Node node, <span style="color: #0000ff">int</span><span style="color: #000000"> i){
</span><span style="color: #008000">//</span><span style="color: #008000">先将节点插入到树中</span>
<span style="color: #0000ff">if</span>(node == <span style="color: #0000ff">null</span><span style="color: #000000">)
</span><span style="color: #0000ff">return</span> <span style="color: #0000ff">new</span> Node(i, 1<span style="color: #000000">);
</span><span style="color: #008000">//</span><span style="color: #008000">插入的值与当前节点值进行比较来确定插入的位置</span>
<span style="color: #0000ff">if</span>(i <<span style="color: #000000"> node.val){
node.LChild </span>=<span style="color: #000000"> insert(node.LChild, i);
</span><span style="color: #008000">//</span><span style="color: #008000">判断是否进行调整</span>
<span style="color: #0000ff">if</span>(height(node.LChild) - height(node.RChild) == 2<span style="color: #000000">){
</span><span style="color: #0000ff">if</span>(i <<span style="color: #000000"> node.LChild.val)
</span><span style="color: #008000">//</span><span style="color: #008000">插入的节点在左孩子的左子树上,则需要进行右旋</span>
node =<span style="color: #000000"> RRotate(node);
</span><span style="color: #0000ff">else</span>
<span style="color: #008000">//</span><span style="color: #008000">插入的节点在左孩子的右子树上,则需要先进行左旋后进行右旋</span>
node =<span style="color: #000000"> LRRotate(node);
}
}
</span><span style="color: #0000ff">else</span><span style="color: #000000">{
node.RChild </span>=<span style="color: #000000"> insert(node.RChild, i);
</span><span style="color: #0000ff">if</span>(height(node.LChild) - height(node.RChild) == -2<span style="color: #000000">){
</span><span style="color: #0000ff">if</span>(i ><span style="color: #000000"> node.RChild.val)
node </span>=<span style="color: #000000"> LRotate(node);
</span><span style="color: #0000ff">else</span><span style="color: #000000">
node </span>=<span style="color: #000000"> RLRotate(node);
}
}
node.height </span>= Math.max(height(node.LChild), height(node.RChild))+1<span style="color: #000000">;
</span><span style="color: #0000ff">return</span><span style="color: #000000"> node;
}
</span><span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span><span style="color: #000000"> main(String[] args) {
</span><span style="color: #0000ff">int</span>[] arr = {1,2,3,4,5,6,7,8,9,10,11,12,13,14<span style="color: #000000">};
AVL avl </span>= <span style="color: #0000ff">new</span><span style="color: #000000"> AVL(arr);
}
}
查考博文
AVL树插入操作实现的更多相关文章
- AVL树插入和删除
一.AVL树简介 AVL树是一种平衡的二叉查找树. 平衡二叉树(AVL 树)是一棵空树,或者是具有下列性质的二叉排序树: 1它的左子树和右子树都是平衡二叉树, 2且左子树和右子树高度之差的 ...
- AVL树相关操作
#include <iostream> using namespace std; //AVL树的节点 template<typename T> class TreeNode { ...
- AVL树插入(Python实现)
建立AVL树 class AVLNode(object): def __init__(self,data): self.data = data self.lchild = None self.rchi ...
- avl树的操作证明
以下用大O表示节点,ABC表示三个集合. 仅分析左子树的情况,因为对称,右子树的情况一样. 插入节点前 O / \ O A / \ B C 插入节点后: O ...
- AVL树Python实现
# coding=utf-8 # AVL树Python实现 def get_height(node): return node.height if node else -1 def tree_mini ...
- 树-二叉搜索树-AVL树
树-二叉搜索树-AVL树 树 树的基本概念 节点的度:节点的儿子数 树的度:Max{节点的度} 节点的高度:节点到各叶节点的最大路径长度 树的高度:根节点的高度 节点的深度(层数):根节点到该节点的路 ...
- AVL树(平衡二叉树)
定义及性质 AVL树:AVL树是一颗自平衡的二叉搜索树. AVL树具有以下性质: 根的左右子树的高度只差的绝对值不能超过1 根的左右子树都是 平衡二叉树(AVL树) 百度百科: 平衡二叉搜索树(Sel ...
- AVL树的插入与删除
AVL 树要在插入和删除结点后保持平衡,旋转操作必不可少.关键是理解什么时候应该左旋.右旋和双旋.在Youtube上看到一位老师的视频对这个概念讲解得非常清楚,再结合算法书和网络的博文,记录如下. 1 ...
- AVL树(查找、插入、删除)——C语言
AVL树 平衡二叉查找树(Self-balancing binary search tree)又被称为AVL树(AVL树是根据它的发明者G. M. Adelson-Velskii和E. M. Land ...
随机推荐
- openstack-kilo--issue(九) heat stacks topology中图形无法正常显示
======声明======= 欢迎转载:转载请注明出处 http://www.cnblogs.com/horizonli/p/6186581.html ==========环境=========== ...
- Linux目录操作
mkdir() #include <sys/stat.h> #include <sys/types.h> int mkdir(const char *pathname, mod ...
- 在win10中创建开机自动登陆的网络驱动器
前提环境: win10系统电脑一台. centos系统电脑一台,在该系统中安装samba,并配置共享. 要解决的问题: 在win10做了网络映射,将centos共享的文件夹设置成本地硬盘.在映射时,也 ...
- SVN报Previous operation has not finished; run 'cleanup' if it was interrupted错误的解决方法
做着项目突然SVN报Previous operation has not finished; run 'cleanup' if it was interrupted,进度又要继续,烦.百度一下发现很多 ...
- JAVA IO 以及 NIO 理解
由于Netty,了解了一些异步IO的知识,JAVA里面NIO就是原来的IO的一个补充,本文主要记录下在JAVA中IO的底层实现原理,以及对Zerocopy技术介绍. IO,其实意味着:数据不停地搬入搬 ...
- BZOJ4152The Captain[DIjkstra]
4152: [AMPPZ2014]The Captain Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 700 Solved: 266[Submit ...
- 第8章 用户模式下的线程同步(3)_Slim读写锁(SRWLock)
8.5 Slim读/写锁(SRWLock)——轻量级的读写锁 (1)SRWLock锁的目的 ①允许读者线程同一时刻访问共享资源(因为不存在破坏数据的风险) ②写者线程应独占资源的访问权,任何其他线程( ...
- 第五章项目:QuickHit
需求概述: 根据输入速率和正确率将玩家分为不同级别,级别越高,一次显示的字符数越多,玩家正确输入一次的得分也越高.如果玩家在规定时间内完成规定次数的输入,正确率达到规定要求,则玩家升级(为了简单起见, ...
- VIM的强大功能
转发地址:http://coolshell.cn/articles/5426.html 简明 Vim 练级攻略 vim的学习曲线相当的大(参看各种文本编辑器的学习曲线),所以,如果你一开始看到的是 ...
- guava函数式编程
[Google Guava] 4-函数式编程 原文链接 译文链接 译者:沈义扬,校对:丁一 注意事项 截至JDK7,Java中也只能通过笨拙冗长的匿名类来达到近似函数式编程的效果.预计JDK8中会有所 ...