平衡二叉树
来源:互联网 发布:博采网络推广怎么做 编辑:程序博客网 时间:2024/06/03 20:03
平衡二叉树简称平衡树,是由Adelson-Velskii和Landis于1962年首先提出的,所以又称为AVL树。他的定义很简单,就是若一棵二叉树的每个左右节点的高度差最多相差1,此二叉树即是平衡二叉树。把二叉树的每个节点的左子树减去右子树定义为该节点的平衡因子。二叉平衡树的平衡因子只能是1、0或者-1。
平衡二叉树是对二叉搜索树(又称为二叉排序树)的一种改进。二叉搜索树有一个缺点就是,树的结构是无法预料的,随意性很大,它只与节点的值和插入的顺序有关系,往往得到的是一个不平衡的二叉树。在最坏的情况下,可能得到的是一个单支二叉树,其高度和节点数相同,相当于一个单链表,对其正常的时间复杂度有O(lb n)变成了O(n),从而丧失了二叉排序树的一些应该有的优点。
当插入一个新的节点的时候,在普通的二叉树中不用考虑树的平衡因子,只要将大于根节点的值插入到右子树,小于节点的值插入到左子树,递归即可。而在平衡二叉树则不一样,在插入节点的时候,如果插入节点之后有一个节点的平衡因子要大于2或者小于-2的时候,他需要对其进行调整。
对于一个平衡的节点,由于任意节点最多有两个儿子,因此高度不平衡时,此节点的两颗子树的高度差2.容易看出,这种不平衡出现在下面四种情况:1、6节点的左子树3节点高度比右子树7节点大2,左子树3节点的左子树1节点高度大于右子树4节点,这种情况成为左左。
2、6节点的左子树2节点高度比右子树7节点大2,左子树2节点的左子树1节点高度小于右子树4节点,这种情况成为左右。
3、2节点的左子树1节点高度比右子树5节点小2,右子树5节点的左子树3节点高度大于右子树6节点,这种情况成为右左。
4、2节点的左子树1节点高度比右子树4节点小2,右子树4节点的左子树3节点高度小于右子树6节点,这种情况成为右右。
从图2中可以可以看出,1和4两种情况是对称的,这两种情况的旋转算法是一致的,只需要经过一次旋转就可以达到目标,我们称之为单旋转。2和3两种情况也是对称的,这两种情况的旋转算法也是一致的,需要进行两次旋转,我们称之为双旋转。
单旋转单旋转是针对于左左和右右这两种情况的解决方案,这两种情况是对称的,只要解决了左左这种情况,右右就很好办了。图3是左左情况的解决方案,节点k2不满足平衡特性,因为它的左子树k1比右子树Z深2层,而且k1子树中,更深的一层的是k1的左子树X子树,所以属于左左情况。
LL
左旋代码分析
/*-----------------------------------------------------------
| node right
| / / ==> / /
| a right node y
| / / / /
| b y a b //左旋
-----------------------------------------------------------*/
static rb_node_t* rb_rotate_left(rb_node_t* node, rb_node_t* root)
{
rb_node_t* right = node->right; //指定指针指向 right<--node->right
if ((node->right = right->left))
{
right->left->parent = node; //好比上面的注释图,node成为b的父母
}
right->left = node; //node成为right的左孩子
if ((right->parent = node->parent))
{
if (node == node->parent->right)
{
node->parent->right = right;
}
else
{
node->parent->left = right;
}
}
else
{
root = right;
}
node->parent = right; //right成为node的父母
return root;
}
RR
RR情况需要左旋解决,如下图所示:
右旋
/*-----------------------------------------------------------
| node left
| / / / /
| left y ==> a node
| / / / /
| a b b y //右旋与左旋差不多,分析略过
-----------------------------------------------------------*/
static rb_node_t* rb_rotate_right(rb_node_t* node, rb_node_t* root)
{
rb_node_t* left = node->left;
if ((node->left = left->right))
{
left->right->parent = node;
}
left->right = node;
if ((left->parent = node->parent))
{
if (node == node->parent->right)
{
node->parent->right = left;
}
else
{
node->parent->left = left;
}
}
else
{
root = left;
}
node->parent = left;
return root;
}
双旋转
对于左右和右左这两种情况,单旋转不能使它达到一个平衡状态,要经过两次旋转。双旋转是针对于这两种情况的解决方案,同样的,这样两种情况也是对称的,只要解决了左右这种情况,右左就很好办了。图4是左右情况的解决方案,节点k3不满足平衡特性,因为它的左子树k1比右子树Z深2层,而且k1子树中,更深的一层的是k1的右子树k2子树,所以属于左右情况。
LR
为使树恢复平衡,我们需要进行两步,第一步,把k1作为根,进行一次右右旋转,旋转之后就变成了左左情况,所以第二步再进行一次左左旋转,最后得到了一棵以k2为根的平衡二叉树树。
RL
RL情况需要右左旋解决(先B右旋转,后A左旋转),如下图所示:
例子:
例子:
例子:
AVL与RBT
AVL是严格平衡树,因此在增加或者删除节点的时候,根据不同情况,旋转的次数比红黑树要多;
红黑是弱平衡的,用非严格的平衡来换取增删节点时候旋转次数的降低;
所以简单说,搜索的次数远远大于插入和删除,那么选择AVL树,如果搜索,插入删除次数几乎差不多,应该选择RB树。
一般的,红黑树,满足以下性质,即只有满足以下全部性质的树,我们才称之为红黑树:
1)每个结点要么是红的,要么是黑的。
2)根结点是黑的。
3)每个叶结点,即空结点(NIL)是黑的。
4)如果一个结点是红的,那么它的俩个儿子都是黑的。
5)对每个结点,从该结点到其子孙结点的所有路径上包含相同数目的黑结点。
- 平衡二叉树平衡法则
- 二叉树--二叉平衡树
- 平衡二叉树的
- 平衡二叉树
- 平衡二叉树
- 平衡二叉树
- 平衡二叉树
- 平衡二叉查找树
- 平衡二叉树 详解
- 平衡二叉树
- 平衡二叉树
- AVL 平衡二叉树
- 平衡二叉树
- 平衡二叉树-红黑树
- 平衡二叉树
- 平衡二叉树
- 平衡二叉树
- 平衡二叉树
- 自己做一款简易的chrome扩展--清除页面广告
- poj_3274 Gold Balanced Lineup(数字哈希)
- ci框架的轮播图
- CGDB显示汇编代码
- Hibernate处理同名实体的方法(映射文件)
- 平衡二叉树
- cocos2dx学习之路----第十四篇(内存管理机制)
- php魔术方法__get和__set详解
- HDOJ 2057 A + B Again(水题,基础)
- js 中this陷阱
- LeetCode 40. Combination Sum II
- Android ADB server didn't ACK * failed to start daemon * 简单有效的解决方案
- softmax 函数
- 多文件上传