AVL树探秘
本文首发于我的公众号 Linux云计算网络(id: cloud_dev) ,专注于干货分享,号内有 10T 书籍和视频资源,后台回复 「1024」 即可领取,欢迎大家关注,二维码文末可以扫。
一、AVL树
AVL树是一种平衡查找树,在前面的两篇文章:二叉搜索树 和 红黑树 中都提到过。由于二叉搜索树在某些特殊情况下是不平衡的(任意一个结点深度过大),因此其一些动态集合操作在最坏情况下的时间复杂度为O(n)。因此提出一些对二叉搜索树效率改进的树结构使最坏时间复杂度降为O(lgn),AVL树和红黑树就是其中的代表,除此之外,还有一些如AA-tree、B-tree、2-3-tree等。使不平衡树变平衡最关键的是找到“平衡条件”,我们已经在前面一篇文章中详述了红黑树的平衡条件是:对节点进行着色,并约束从根节点到任何叶子节点的长度,其中,约定了5条规定,稍显复杂。而AVL树的平衡条件则显得格外简单:只用保证左右子树的高度不超过1即可。
二、AVL树的实现
1、数据结构
节点类:因为需要控制节点的高度,所以高度是一个属性。指针域包括left、right,parent可以包括也可以不要,本文的实现中,我们包括parent。
struct AVLNode {
AVLNode *Parent;
AVLNode *Left;
AVLNode *Right;
int m_nHeight;
int m_nValue;
};
2、节点的平衡
当插入新的节点或者删除节点时,会导致树的不平衡,即其中有节点的左右子树的高度相差>1,这个时候就需要调节树使之平衡。可能出现不平衡的情况总共有以下几种:
////////////////////////////////////////
a a a a
/ / \ \
b b b b
/ \ / \
c c c c
LL LR RL RR
//////////////////////////////////////
总共就只会出现这四种情况,对这四种情况的分类很多书上有各自的说法。其中1、4和2、3是对称的,我们用LL、LR、RL、RR来分别表示,要使这几种情况平衡,我们只用做简单的旋转操作就OK了,针对1、4,有的说法是做单旋,有的说法是外旋,而2、3,则做双旋或内旋,不管是哪种说法,其本质是不变的。在我们的实现中,采用单旋和双旋,双旋就是做两次单旋:
//单旋
void _LeftRotation( AVLNode *node );
void _RightRotation( AVLNode *node ); //双旋
void _LeftRightRotation( AVLNode *node );
void _RightLeftRotation( AVLNode *node );
3、平衡的修复
在插入节点和删除节点的时候,会破坏树的平衡条件,这个时候就需要修复。我们采用尽可能少地改动原有代码的原则来修复,这个原则和红黑树的修复操作是一致的,即插入和删除操作我们依然沿用二叉搜索树的实现,只在后面添加修复的代码即可。
如何修复?首先,插入和删除会破坏节点的高度,所以,应更新结点的高度;其次,插入和删除破坏了树中某些节点的平衡,所以,应针对上面四种情况分别平衡节点。所以,这里就需要两个函数:一个更新结点高度的函数UpdateHeight( AVLNode *node );一个平衡节点的函数: BalanceNode( AVLNode *node )。
void AVLTree::_UpdateHeight( AVLNode *node )
{
AVLNode *l = node->Left, *r = node->Right; if ( l && r )
node->m_nHeight = max( l->m_nHeight, r->m_nHeight ) + ;
else if ( l )
node->m_nHeight = l->m_nHeight + ;
else if ( r )
node->m_nHeight = r->m_nHeight + ;
else node->m_nHeight = ;
}
//////////////////////////////////////////////////////////////////////////
// a a a a
// / / \ \
// b b b b
// / \ / \
// c c c c
// LL LR RL RR
//////////////////////////////////////////////////////////////////////////
void AVLTree::_BalanceNode( AVLNode *node )
{
int nBlance = _GetBalanceFactor( node );
if ( nBlance > ) { //L
//(1)
//if ( _GetBalanceFactor( node->Left ) < 0 ) //LR
// _LeftRightRotation( node ); //双旋
//else _RightRotation( node ); //LL //单旋 //(2)
if ( _GetBalanceFactor( node->Left ) < )
_LeftRotation( node->Left );
_RightRotation( node );
}
if ( nBlance < - ) { //R
if ( _GetBalanceFactor( node ) > ) { //RL
_RightRotation( node->Right );
}
_LeftRotation( node );
}
} //平衡因子(左右子树的高度差)
int AVLTree::_GetBalanceFactor( AVLNode *node )
{
AVLNode *l = node->Left, *r = node->Right; if ( l && r )
return l->m_nHeight - r->m_nHeight;
else if ( l )
return l->m_nHeight + ;
else if ( r )
return -r->m_nHeight - ;
else return ;
}
基本上该注意的点都提到了,下面附上详细代码实现:
#ifndef __AVL_TREE_H_
#define __AVL_TREE_H_ class AVLTree
{
private:
struct AVLNode {
AVLNode *Parent;
AVLNode *Left;
AVLNode *Right;
int m_nHeight;
int m_nValue;
};
public:
AVLTree(AVLNode *root = NULL):m_pRoot(root) {}
~AVLTree() {
_RecursiveDeleteNode(m_pRoot);
} bool Search( const int search_value ) const;
bool Insert( const int value );
bool Delete( const int delete_value ); void Print() const; private:
void _RecursiveDeleteNode(AVLNode *node) {
if ( node ) {
_RecursiveDeleteNode( node->Left );
_RecursiveDeleteNode( node->Right );
delete node;
}
node = NULL;
} void _DeleteNode( AVLNode *delete_node );
void _Delete_Transplant( AVLNode *unode, AVLNode *vnode );
void _InsertNode( const int insert_value );
AVLNode * _SearchNode( AVLNode *node, const int search_value ) const; //单旋
void _LeftRotation( AVLNode *node );
void _RightRotation( AVLNode *node ); //双旋
void _LeftRightRotation( AVLNode *node );
void _RightLeftRotation( AVLNode *node ); AVLNode* Minimum( AVLNode *node ); //树高
int _Height ( AVLNode *node );
void _UpdateHeight( AVLNode *node );
//平衡因子
int _GetBalanceFactor( AVLNode *node );
//平衡失去平衡的节点
void _BalanceNode( AVLNode *node ); void _Print ( AVLNode *node ) const; private:
AVLNode *m_pRoot; };
#endif//__AVL_TREE_H_
#include <iostream>
#include <algorithm>
using namespace std; #include "AVL_Tree.h" bool AVLTree::Search( const int search_value ) const
{
return _SearchNode( m_pRoot, search_value ) != NULL;
} AVLTree::AVLNode * AVLTree::_SearchNode( AVLNode *node, const int search_value ) const
{
while ( node && search_value != node->m_nValue ) {
if ( search_value < node->m_nValue )
node = node->Left;
else
node = node->Right;
}
return node;
} bool AVLTree::Insert( const int value )
{
//该值已存在
if ( Search( value ) )
return false;
else {
_InsertNode( value );
return true;
}
} void AVLTree::_InsertNode( const int insert_value )
{
AVLNode *node = m_pRoot;
AVLNode *temp_node = NULL; //先找到待插入节点的位置
while ( node ) {
temp_node = node;
node = ( insert_value < node->m_nValue )?node->Left:node->Right;
} AVLNode *insert_node = new AVLNode();
insert_node->m_nValue = insert_value; insert_node->Parent = temp_node; //空树
if ( temp_node == NULL )
m_pRoot = insert_node;
else {
if ( insert_value < temp_node->m_nValue )//左子树
temp_node->Left = insert_node;
else
temp_node->Right = insert_node; //右子树
} //更新插入节点的高度和平衡节点
while ( insert_node ) {
_UpdateHeight( insert_node );
_BalanceNode( insert_node );
insert_node = insert_node->Parent;
}
} bool AVLTree::Delete( const int delete_value )
{
AVLNode *delete_node = _SearchNode( m_pRoot, delete_value ); //节点不存在
if ( delete_node == NULL )
return false;
else {
_DeleteNode( delete_node );
return true;
}
} void AVLTree::_DeleteNode( AVLNode *delete_node )
{
if ( delete_node->Left == NULL )
_Delete_Transplant( delete_node, delete_node->Right );
else if ( delete_node->Right == NULL )
_Delete_Transplant( delete_node, delete_node->Left );
else {
AVLNode *min_node = Minimum( delete_node->Right );
if ( min_node->Parent != delete_node ) {
_Delete_Transplant( min_node, min_node->Right );
min_node->Right = delete_node->Right;
min_node->Right->Parent = min_node;
}
_Delete_Transplant( delete_node, min_node );
min_node->Left = delete_node->Left;
min_node->Left->Parent = min_node;
} //更新结点的高度和平衡节点
while ( delete_node ) {
_UpdateHeight( delete_node );
_BalanceNode( delete_node );
delete_node = delete_node->Parent;
}
} void AVLTree::_Delete_Transplant( AVLNode *unode, AVLNode *vnode )
{
if ( unode->Parent == NULL )
m_pRoot = vnode;
else if ( unode == unode->Parent->Left )
unode->Parent->Left = vnode;
else
unode->Parent->Right = vnode;
if ( vnode )
vnode->Parent = unode->Parent;
} AVLTree::AVLNode* AVLTree::Minimum( AVLNode *node )
{
while ( node->Left )
node = node->Left;
return node;
} //树高
int AVLTree::_Height( AVLNode *node )
{
return node->m_nHeight;
} //平衡因子(左右子树的高度差)
int AVLTree::_GetBalanceFactor( AVLNode *node )
{
AVLNode *l = node->Left, *r = node->Right; if ( l && r )
return l->m_nHeight - r->m_nHeight;
else if ( l )
return l->m_nHeight + ;
else if ( r )
return -r->m_nHeight - ;
else return ;
} void AVLTree::_UpdateHeight( AVLNode *node )
{
AVLNode *l = node->Left, *r = node->Right; if ( l && r )
node->m_nHeight = max( l->m_nHeight, r->m_nHeight ) + ;
else if ( l )
node->m_nHeight = l->m_nHeight + ;
else if ( r )
node->m_nHeight = r->m_nHeight + ;
else node->m_nHeight = ;
} //////////////////////////////////////////////////////////////////////////
// a a a a
// / / \ \
// b b b b
// / \ / \
// c c c c
// LL LR RL RR
//////////////////////////////////////////////////////////////////////////
void AVLTree::_BalanceNode( AVLNode *node )
{
int nBlance = _GetBalanceFactor( node );
if ( nBlance > ) { //L
//(1)
//if ( _GetBalanceFactor( node->Left ) < 0 ) //LR
// _LeftRightRotation( node ); //双旋
//else _RightRotation( node ); //LL //单旋 //(2)
if ( _GetBalanceFactor( node->Left ) < )
_LeftRotation( node->Left );
_RightRotation( node );
}
if ( nBlance < - ) { //R
if ( _GetBalanceFactor( node ) > ) { //RL
_RightRotation( node->Right );
}
_LeftRotation( node );
}
} //单旋
//左旋
void AVLTree::_LeftRotation( AVLNode *node )
{
if ( node->Right == NULL )
return; AVLNode *temp_node = node->Right; //补
node->Right = temp_node->Left;
if ( temp_node->Left )
temp_node->Left->Parent = node; //提
temp_node->Parent = node->Parent;
if ( node->Parent == NULL )
m_pRoot = temp_node;
else if ( node == node->Parent->Left )
node->Parent->Left = temp_node;
else node->Parent->Right = temp_node; //降
temp_node->Left = node;
node->Parent = temp_node; _UpdateHeight( node );
_UpdateHeight( temp_node );
} //右旋
void AVLTree::_RightRotation( AVLNode *node )
{
if ( node->Left == NULL )
return; AVLNode *temp_node = node->Left; //补
node->Left = temp_node->Right;
if ( temp_node->Right )
temp_node->Right->Parent = node; //提
temp_node->Parent = node->Parent;
if ( node->Parent == NULL )
m_pRoot = temp_node;
else if ( node == node->Parent->Left )
node->Parent->Left = temp_node;
else node->Parent->Right = temp_node; //降
temp_node->Right = node;
node->Parent = temp_node; _UpdateHeight( node );
_UpdateHeight( temp_node );
} //双旋
//LR
void AVLTree::_LeftRightRotation( AVLNode *node )
{
_LeftRotation( node->Left );
_RightRotation( node );
} //RL
void AVLTree::_RightLeftRotation( AVLNode *node )
{
_RightRotation( node->Right );
_RightRotation( node );
} void AVLTree::Print() const
{
_Print(m_pRoot);
}
//打印
void AVLTree::_Print ( AVLNode *node ) const
{
if ( node->Parent == NULL )
cout << "root: " << node->m_nValue << endl;
else if ( node == node->Parent->Left )
cout << "left: " << node->m_nValue << ", parent: " << node->Parent->m_nValue << endl;
else cout << "right: " << node->m_nValue << ", parent: " << node->Parent->m_nValue << endl;
if ( node->Left )
_Print( node->Left );
if ( node->Right )
_Print( node->Right );
} int main()
{
AVLTree al;
for (int i = ; i < ; i ++) {
al.Insert(i); }
al.Print();
for (int i = ; i < ; i += ) {
al.Delete(i);
al.Print();
}
return ;
}
我的公众号 「Linux云计算网络」(id: cloud_dev),号内有 10T 书籍和视频资源,后台回复 「1024」 即可领取,分享的内容包括但不限于 Linux、网络、云计算虚拟化、容器Docker、OpenStack、Kubernetes、工具、SDN、OVS、DPDK、Go、Python、C/C++编程技术等内容,欢迎大家关注。
AVL树探秘的更多相关文章
- 算法与数据结构(十一) 平衡二叉树(AVL树)
今天的博客是在上一篇博客的基础上进行的延伸.上一篇博客我们主要聊了二叉排序树,详情请戳<二叉排序树的查找.插入与删除>.本篇博客我们就在二叉排序树的基础上来聊聊平衡二叉树,也叫AVL树,A ...
- AVL树原理及实现(C语言实现以及Java语言实现)
欢迎探讨,如有错误敬请指正 如需转载,请注明出处http://www.cnblogs.com/nullzx/ 1. AVL定义 AVL树是一种改进版的搜索二叉树.对于一般的搜索二叉树而言,如果数据恰好 ...
- AVL树
AVL树 在二叉查找树(BST)中,频繁的插入操作可能会让树的性能发生退化,因此,需要加入一些平衡操作,使树的高度达到理想的O(logn),这就是AVL树出现的背景.注意,AVL树的起名来源于两个发明 ...
- AVL树的平衡算法(JAVA实现)
1.概念: AVL树本质上还是一个二叉搜索树,不过比二叉搜索树多了一个平衡条件:每个节点的左右子树的高度差不大于1. 二叉树的应用是为了弥补链表的查询效率问题,但是极端情况下,二叉搜索树会无限接近 ...
- 【数据结构】平衡二叉树—AVL树
(百度百科)在计算机科学中,AVL树是最先发明的自平衡二叉查找树.在AVL树中任何节点的两个子树的高度最大差别为一,所以它也被称为高度平衡树.查找.插入和删除在平均和最坏情况下都是O(log n).增 ...
- 数据结构图文解析之:AVL树详解及C++模板实现
0. 数据结构图文解析系列 数据结构系列文章 数据结构图文解析之:数组.单链表.双链表介绍及C++模板实现 数据结构图文解析之:栈的简介及C++模板实现 数据结构图文解析之:队列详解与C++模板实现 ...
- 数据结构之平衡二叉树(AVL树)
平衡二叉树(AVL树)定义如下:平衡二叉树或者是一棵空树,或者是具有以下性质的二叉排序树: (1)它的左子树和右子树的高度之差绝对值不超过1: (2)它的左子树和右子树都是平衡二叉树. AVL树避免了 ...
- PAT树_层序遍历叶节点、中序建树后序输出、AVL树的根、二叉树路径存在性判定、奇妙的完全二叉搜索树、最小堆路径、文件路由
03-树1. List Leaves (25) Given a tree, you are supposed to list all the leaves in the order of top do ...
- 论AVL树与红黑树
首先讲解一下AVL树: 例如,我们要输入这样一串数字,10,9,8,7,15,20这样一串数字来建立AVL树 1,首先输入10,得到一个根结点10 2,然后输入9, 得到10这个根结点一个左孩子结点9 ...
随机推荐
- BZOJ3122: [Sdoi2013]随机数生成器(BSGS)
题意 题目链接 Sol 这题也比较休闲. 直接把\(X_{i+1} = (aX_i + b) \pmod P\)展开,推到最后会得到这么个玩意儿 \[ a^{i-1} (x_1 + \frac{b}{ ...
- JMeter 内置日期(时间)函数总结
JMeter 内置日期(时间)函数总结 by:授客 QQ:1033553122 1. 测试环境 apache-jmeter-3.3 下载地址: http://jmeter.apache.org/c ...
- Python高级应用(3)—— 为你的项目添加验证码
验证码简介 验证码的作用: 验证码在现在来说,是很常见的东西,可以一定程度的保护网站,比如防止网络爬虫恶意爬取网站数据啊,减少低级的攻击啊什么的.但是高级点的骚操作还是不太好防范,所以现在的验证码平台 ...
- 【eclipse】mybatis配置文件创建与mapper接口文件创建
什么是mybatis: MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过程以及高级映射. mybatis配置文件: <?xml version="1.0" ...
- python3 Queue(单向队列)
创建队列 import queue q = queue.Queue() empty(如果队列为空,返回True) import queue q = queue.Queue() print(q.empt ...
- redhat yum ISO 本地源
先将ISO文件挂载起来: [root@racdb1 ~]# mount -o loop /opt/soft/rhel-server-6.8-x86_64-dvd.iso /mnt/iso [root@ ...
- OLW (Open Live Writer)安装代码高亮插件方法(简明)
1.首先下载OLW代码高亮插件,请点击--->OLW代码高亮插件 2.在你安装OLW的目录下(顺便说一下默认的安装目录为C:\Users\你的用户名\AppData\Local\OpenLive ...
- Scrapy案例02-腾讯招聘信息爬取
目录 1. 目标 2. 网站结构分析 3. 编写爬虫程序 3.1. 配置需要爬取的目标变量 3.2. 写爬虫文件scrapy 3.3. 编写yield需要的管道文件 3.4. setting中配置请求 ...
- Linux Collection:文本编辑问题
PAS 删除文本中的^M标记 由于历史原因,不同操作系统使用不同的方式表示文件的换行符\n.现代计算机系统中的文件换行和早期的打字机有关,主要和两个控制符有关:line feed (LF) ,carr ...
- Oracle 查询重复索引列
SELECT /*+ rule */ a .table_owner, a.table_name, a.index_owner, a.index_name, column_name_list, colu ...