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 ...
随机推荐
- react native windows开发环境搭建(一)
ReactNative分为服务器端和手机端loader程序,Android版有3种代码:js代码,java代码和c++代码,主要是编写的是js代码,如果框架功能不足就需要编写原生的java代码来扩展, ...
- 彻底理解JavaScript原型
原型是JavaScript中一个比较难理解的概念,原型相关的属性也比较多,对象有"[[prototype]]"属性,函数对象有"prototype"属性,原型对 ...
- MMORPG大型游戏设计与开发(UI SYSTEM SHOW)
接下来一段时间,这些文件可能不再更新,期间我会学习和掌握一些前端知识.虽然我非常欣赏剑侠网络版叁和九阴真经的画面,但是那是一个庞大的游戏引擎,一般人是无法窥伺的,除非你是天才而且要拥有机器毫无中断的毅 ...
- 【转载】SweetAlert2 使用
SweetAlert2是一款功能强大的纯Js模态消息对话框插件.SweetAlert2用于替代浏览器默认的弹出对话框,它提供各种参数和方法,支持嵌入图片,背景,HTML标签等,并提供5种内置的情景类, ...
- ACCP 结业考试
1) 在SQL Server 中,为数据库表建立索引能够(C ). 索引:是SQL SERVER编排数据的内部方法,是检索表中数据的直接通道 建立索引的作用:大大提高了数据库的检索速度,改善数据库性能 ...
- java 25 - 2 网络编程之 网络通信三要素
网络通信三要素 IP地址: InetAddress 网络中设备的标识,不易记忆,可用主机名(计算机的标识号) 端口号: 用于标识进程的逻辑地址,不同进程的标识(正在运行的软件的标识号) 传输协议: 通 ...
- Android中实现如下多语言选择Radiobutton效果
手边的samsung手机设置多语言的方式一般是点击设置多语言的一栏后进入到多语言选择界面,选择完成之后当前的语言环境用小字方式直接显示在设置多语言栏的下方.另一种选择多语言的方式如上图所示,我也在系统 ...
- grunt-contrib-uglify压缩插件的常用配置属性
mangle:false(不混淆变量名和方法名,保留原有的名字),如果不配置,默认混淆,就是将所有方法名和变量都用a,b,c等字母替换 preserveComments : 'all'(不删除注释,还 ...
- HTML 学习笔记 CSS样式(边框)
元素的边框(border)是围绕元素内容和内边距的一条或多条线 CSS border 属性允许你规定边框的样式 宽度和颜色 CSS 边框 在 HTML 中,我们使用表格来创建文本周围的边框,但是通过使 ...
- wk_04
函数 函数是对程序逻辑进行结构化或过程化的一直编程方法.能将整块代码巧妙的隔离成易于管理的小块,把重复代码放到函数中而不是进行大量的拷贝--这样既能节省空间,也有助于保持一致性,因为你只需要改变单个的 ...