平衡二叉查找树插入节点操作( AVLTree ):旋转、调整平衡
AVL树的插入
在向一棵本来高度平衡的AVL树中插入一个新节点时,如果树中某个结点的平衡因子的绝对值 > 1,则出现了不平衡。设新插入结点为P,从结点P到根节点的路径上,每个结点为根的子树的高度都可能增加1,因此在每执行一次二叉搜索树的插入运算后,都需从新插入的结点P开始,沿该结点插入的路径向根节点方向回溯,修改各结点的平衡因子,调整整棵树的高度,恢复被破坏的平衡性质。
AVL树插入算法:
新节点P的平衡因子为0,但其双亲结点Pr的平衡因子有三种情况:
1、结点Pr的平衡因子为0
在Pr的较矮的子树上插入新节点,结点Pr平衡,其高度没有增加,此时从Pr到根路径上各结点为根的子树的高度不变,即各结点的平衡因子不变,结束平衡化处理。
2、结点Pr的平衡因子的绝对值为1;
插入前Pr的平衡因子为0,插入后以Pr为根的子树没有失去平衡,但该子树的高度增
加,需从该结点Pr向根节点方向回溯,继续查看Pr的双亲结点的平衡性。
3、结点Pr的平衡因子的绝对值为2
新节点在较高的子树插入,需要做平衡化处理:
若Pr = 2,说明右子树高,设Pr的右子树为q
当q的平衡因子为1,执行左单旋转
当q的平衡因子为-1,执行先右后左双旋转
若Pr = -2,说明左子树高,设Pr的左子树为q
当q的平衡因子为-1,执行右单旋转
当q的平衡因子为1,执行先左后右双旋转
具体代码:
#include<iostream>
using namespace std;
template<class K, class V>
struct AVLTreeNode
{
AVLTreeNode<K, V>* _pleft;
AVLTreeNode<K, V>* _pright;
AVLTreeNode<K, V>* _pParent;
K _key;
V _value;
int _bf;
AVLTreeNode(const K& key, const V& value)
:_pleft(NULL)
, _pright(NULL)
,_pParent(NULL)
, _key(key)
,_value(value)
,_bf(0)
{}
};
template<class K, class V>
class AVLTree
{
typedef AVLTreeNode<K, V> Node;
public:
AVLTree()
:_pRoot(NULL)
{}
AVLTree(const AVLTree<K, V>& t);
AVLTree<K, V>& operator=(const AVLTree<K, V>& t);
~AVLTree()
{
_Destory(_pRoot);
}
public:
bool Insert(const K& key, const V& value)
{
if(NULL == _pRoot)
{
_pRoot = new Node(key, value);
return true;
}
//寻找插入位置
Node* parent = NULL;
Node* pCur = _pRoot;
while(pCur)
{
if(key < pCur->_key)
{
parent = pCur;
pCur = pCur->_pleft;
}
else if(key > pCur->_key)
{
parent = pCur;
pCur = pCur->_pright;
}
else
return false;
}
pCur = new Node(key, value);
//插入
if(key < parent->_key)
{
parent->_pleft = pCur;
}
else
{
parent->_pright = pCur;
}
pCur->_pParent = parent;
//更新平衡因子
while(parent)
{
if(parent->_pleft == pCur)
{
parent->_bf--;
}
else
{
parent->_bf++;
}
if(parent->_bf == 0)
{
break;
}
else if(1 == parent->_bf || parent->_bf == -1)
{
pCur = parent;
parent = pCur->_pParent;
}
else
{
if(parent->_bf == 2)
{
if(pCur->_bf == 1)
_RotateL(parent);
else if(pCur->_bf == -1)
_RotateRL(parent);
}
else if(parent->_bf == -2)
{
if(pCur->_bf == -1)
_RotateR(parent);
else if(pCur->_bf == 1)
_RotateLR(parent);
}
break;
}
}
return true;
}
void Inorder() //中序遍历
{
_Inorder(_pRoot);
cout << endl;
}
bool IsBalance() //判断是否平衡
{
int height = 0;
return _IsBalance(_pRoot, height);
}
private:
void _RotateR(Node* parent)
{
Node* subL = parent->_pleft;
Node* subLR = subL->_pright;
parent->_pleft = subLR;
if(subLR)
subLR->_pParent = parent;
subL->_pright = parent;
Node* pParent = parent->_pParent;
parent->_pParent = subL;
if(pParent == NULL)
{
_pRoot = subL;
subL->_pParent = NULL;
}
else
{
if(pParent->_pleft == parent)
{
pParent->_pleft = subL;
}
else
{
pParent->_pright = subL;
}
subL->_pParent = pParent;
}
subL->_bf = parent->_bf = 0;
}
void _RotateL(Node* parent)
{
Node* subR = parent->_pright;
Node* subRL = subR->_pleft;
parent->_pright = subRL;
if(subRL)
subRL->_pParent = parent;
subR->_pleft = parent;
Node* pParent = parent->_pParent;
parent->_pParent = subR;
if(pParent == NULL)
{
_pRoot = subR;
subR->_pParent = NULL;
}
else
{
if(pParent->_pleft == parent)
{
pParent->_pleft = subR;
}
else
{
pParent->_pright = subR;
}
subR->_pParent = pParent;
}
subR->_bf = parent->_bf = 0;
}
void _RotateRL(Node*& parent)
{
Node* subR = parent->_pright;
Node* subRL = subR->_pleft;
_RotateR(subR);
_RotateL(parent);
int bf = subRL->_bf;
if (bf == 0)
{
subRL->_bf = parent->_bf = subR->_bf = 0;
}
else if (bf == -1)
{
subRL->_bf = 0;
parent->_bf = 1;
subR->_bf = 0;
}
else if (bf == 1)
{
subRL->_bf = 0;
parent->_bf = 0;
subR->_bf = 1;
}
}
void _RotateLR(Node*& parent)
{
Node* subL = parent->_pleft;
Node* subLR = subL->_pright;
_RotateL(subL);
_RotateR(parent);
int bf = subLR->_bf;
if (bf == 0)
{
subLR->_bf = parent->_bf = subL->_bf = 0;
}
else if (bf == 1)
{
subLR->_bf = 0;
parent->_bf = 1;
subL->_bf = 0;
}
else if (bf == -1)
{
subLR->_bf = 0;
parent->_bf = 0;
subL->_bf = -1;
}
}
void _Destory(Node*& pRoot)
{
if (_pRoot == NULL)
return;
_Destory(pRoot->_pleft);
_Destory(pRoot->_pright);
delete pRoot;
pRoot = NULL;
}
protected:
void _Inorder(Node* pRoot) //中序
{
if (pRoot == NULL)
{
return;
}
_Inorder(pRoot->_pleft);
cout << pRoot->_key << " ";
_Inorder(pRoot->_pright);
}
bool _IsBalance(Node* pRoot, int& height)
{
if (pRoot == NULL)
{
height = 0;
return true;
}
int left, right;
if (_IsBalance(pRoot->_pleft, left) && _IsBalance
(pRoot->_pright, right)
&& abs(right - left) < 2)
{
height = left > right ? left + 1 : right + 1;
if (pRoot->_bf != right - left)
{
cout << "平衡因子异常:" << pRoot->_key
<< endl;
return false;
}
return true;
}
else
{
return false;
}
}
size_t _Height(Node* pRoot) //高度
{
if (pRoot == NULL)
{
return 0;
}
int l = _Height(pRoot->_pleft);
int r = _Height(pRoot->_pright);
return l > r ? l + 1 : r + 1;
}
private:
Node* _pRoot;
};
int main()
{
AVLTree<int, int> t;
t.Insert(3,3);
t.Insert(7,7);
t.Insert(11,11);
t.Insert(14,14);
t.Insert(15,15);
t.Insert(18,18);
t.Insert(16,16);
t.Insert(26,26);
t.Insert(9,9);
t.Inorder();
cout << "IsBalance? " << t.IsBalance() << endl;
system("pause");
return 0;
}
平衡二叉查找树插入节点操作( AVLTree ):旋转、调整平衡相关推荐
- 双链表(插入节点操作)
在双链表L中第i个位置插入值域为e的结点. 双链表的存储结构定义: typedef struct DLinkList{int data;DLinkList * prior;DLinkList * ne ...
- java二叉树插入节点_[javaSE] 数据结构(二叉查找树-插入节点)
public class BSTree>{private BSTNodemRoot;/*** 定义二叉树 * *@authortaoshihan *@param **/ public class ...
- Algorithm:树相关算法(BBT/BST/B树/R树)简介(二叉查找树、二叉查找树的插入节点、二叉查找树的删除、二叉树的遍历、平衡二叉树)C 语言实现
Algorithm:树相关算法(BBT/BST/B树/R树)简介(二叉查找树.二叉查找树的插入节点.二叉查找树的删除.二叉树的遍历.平衡二叉树)C++语言实现 目录 树的基础知识 1.二叉树的遍-前序 ...
- 【AVL树】AVL树的插入操作以及旋转
在讲解AVL树之前必须了解二叉搜索树, 可以看我之前的博客:二叉搜索树 AVL树是在二叉搜索树的基础上,在向二叉树排序树中插入新的结点,如果保证每个结点的左右子树的高度差的绝对值不超过1,即需要在插入 ...
- Java之HashMap经典算法-红黑树(插入节点平衡调整,左旋转,右旋转)
1. 红黑树的优势 有了二叉搜索树,为什么还需要平衡二叉树? 二叉搜索树容易退化成一条链,这时,查找的时间复杂度从 O(log2N)O(log_2N)O(log2N) 将退化成 O(N)O(N )O ...
- 超简单理解自平衡二叉查找树的 旋转 是什么?
首先给大家科普下基础知识 (双旋转的时候,LR左右,RL右左,且首转以尾根节点为旋转中心,第二次旋转以尾根节点的父节点为旋转中心) 一:什么情况下二叉查找树不平衡? 答:一个节点的左子树与右子树的高度 ...
- jquery的DOM节点操作(创建和插入元素节点)
1.创建元素节点 2.插入节点 动态创建新元素节点后,需要执行插入或追加操作,否则不会在页面显示出来. 按照元素的层次关系来分,可以分为内部和外部两种方法 元素内部插入子节点 元素内部插入子节点有两种 ...
- jquery 元素节点操作 - 创建节点、插入节点、删除节点
jquery的节点操作说明 前面的篇章对于jquery的元素操作大部分是使用html()的方式来操作,这种直接使用字符串创建的方式也是性能最高的. 使用html()操作节点 首先编写一个div包含一个 ...
- java document创建节点_javasript 的DOM 节点操作:创建,插入,删除,复制以及查找节点...
DOM 含义: DOM 是文档对象模型(Document Object Model) 是一种基于浏览器编程的一套API 接口,我W3C 出台推荐的标准.其赋予了JS 操作节点的能力,当网页被加载时,浏 ...
最新文章
- :before和::before的区别
- 自动驾驶中,激光雷达点云如何做特征表达
- 在 Java 的反射中,Class.forName 和 ClassLoader 的区别
- 7-zip来解压大于4G以上打包文件
- php分页代码 页数太多,php google或baidu分页代码
- 小小总结一下目前的财政
- python获取类的类属性_Python中如何获取类属性的列表
- 由.Net类库提供的农历计算(C#农历)
- 也说说angularJs里的evalAsync
- C#中手动引用COM组建的例子
- 搭建自已的聊天服务器Rocket.Chat
- 2012-11-25 3:00 发喜讯,终于把S5pv210 VGA 分辨率提升到1440 x 900/1920 x 1080了!
- 英语听力软件测试自学,每日英语听力应该怎么学习?
- Android 蓝牙HOGP协议(基于ble-gatt蓝牙)连接流程分析--framework-jni-btif-bta-btm-hci -- 全网最详细(二)
- 计算机系统启动项设置密码,电脑开机第一道密码怎么设置 - 卡饭网
- react插件,树状图(可自由定义子节点结构,大小,样式)
- 网页设计的秘诀:如何用颜色烘托情感
- 数据分析之excel和finebi报表可视化对比
- 为什么Microsoft账号登录显示暂时停用你的账户_苹果手机显示 Apple ID 被停用该如何恢复?...
- H3CSE路由-IPv6路由协议
热门文章
- ASP.NET状缓存Cache的应用-提高数据库读取速度
- 最长公共子序列|最长公共子串|最长重复子串|最长不重复子串|最长回文子串|最长递增子序列|最大子数组和...
- 告诉你银行在年底为存储做的小动作
- 农业部部署农业大数据发展工作 评:对农业现代化很重要
- FB宣布将回购60亿美元股票 首席会计官将离职
- Ios: 如何保護iOS束文件屬性列表,圖像,SQLite,媒體文件
- android传递数据bundle封装传递map对象
- 替换WordPress调用的Google前端库为360镜像的库
- 5shift shell
- Unique Binary Search Trees