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 ...
随机推荐
- 烂泥:mysql5.5主从同步复制配置
本文由秀依林枫提供友情赞助,首发于烂泥行天下. 在上篇文章<烂泥:学习mysql数据库主从同步复制原理>中,我们介绍了有关mysql主从复制的基本原理.在这篇文章中,我们来实际测试下mys ...
- yum或apt基本源设置指南
关于: 管理Linux服务器的运维或开发人员经常需要安装软件,最常用方式应该是通过Linux系统提供的包管理工具来在线安装,比如centos的yum,ubuntu或debian的apt-get.当然这 ...
- height:100%不起作用(无效),div全屏
当父容器是body时,height:100%不起作用(无效),解决办法:在css代码段中添加 html, body{ margin:0; height:100%; } 实现div全屏的时候需要上面那段 ...
- 大话设计模式C++版——观察者模式
观察者模式是一种类似于消息分发的模式,用于一个任务需要被多个对象监听的场景,或者成员对象需要反向通知类对象的情况,是一种很有用的设计模式. 这里以大话设计模式中的例子为例,办公室员工A.B.C在 ...
- Openxml入门---Openxm读取Excel数据
Openxml读取Excel数据: 有些问题,如果当Cell 里面是 日期和浮点型的话,对应的Cell.DataType==Null,对应的时间会转换为一个浮点型,对于这块可以通过DateTime.F ...
- 用pygame学习初级python(二) 15.5.11
闲得无聊,对第一版的东西做了一些修改,让它更像一个游戏,也具有一些可玩性. 项目的github地址:https://github.com/lfkdsk/BrainHole_pygame 1.人物类进行 ...
- R语言学习笔记(二)
今天主要学习了两个统计学的基本概念:峰度和偏度,并且用R语言来描述. > vars<-c("mpg","hp","wt") &g ...
- 【转】最长回文子串的O(n)的Manacher算法
Manacher算法 首先:大家都知道什么叫回文串吧,这个算法要解决的就是一个字符串中最长的回文子串有多长.这个算法可以在O(n)的时间复杂度内既线性时间复杂度的情况下,求出以每个字符为中心的最长回文 ...
- luogu[1135]奇怪的电梯
题目描述 呵呵,有一天我做了一个梦,梦见了一种很奇怪的电梯.大楼的每一层楼都可以停电梯,而且第i层楼(1<=i<=N)上有一个数字Ki(0<=Ki<=N).电梯只有四个按钮:开 ...
- NSArray遍历和修改崩溃
//一.代码 NSArray *array = [self.dataList mutableCopy]; 或 NSArray *array = [NSArray arrayWithArray:self ...