红黑树

 

 

 

 

红黑树

由于二叉搜索树不加限制的情况下在处理基本动态集合操作时,可能使得二叉树的高度变得越来越大,效率有可能比线性表执行效率还慢。 红黑树(R-B Tree)是 “平衡” 二叉搜索树的一种方式,即对二叉搜索树的基本动态集合操作进行了限制(限制其任意操作都要尽可能的保持 树的高度 合理化),那么将二叉搜索树限制成什么样呢,看定义。


红黑树的定义:
一棵红黑树是满足下面红黑性质的二叉搜索树:
(1)每个结点或是RED,或是BLACK
(2)根结点是BLACK
(3)每个(NULL)叶子结点为BLACK
(4)如果一个结点是RED,那么其两个子结点都是BLACK
(5)从任意一个结点到其所有后代叶结点的简单路径上,黑高(bh不包括本身)相同


【为了满足定义, 除了在二叉搜索树结构体中的key left right parent 外, 还要有一个 color元素。同时,所以内部结点的孩子为NULL的结点都将指向一个 哨兵(T.NULL),即,这个结点是所有内部结点中叶结点的孩子和根结点的父亲。】

 

 

 

 

 

 

 

 


问题一、红黑树为什么能将二叉搜索树限制的比较“好”呢?

由于对二叉搜索树进行上述定义的限制后就是一个名正言顺的红黑树了,这个红黑树具有如下性质,从而使得二叉搜索树不再那么放纵。
(1)在一棵黑高为k的红黑树中,内部结点最少为 2^(k+1) - 1,最多为 2^(2*k+1 ) - 1
【有性质5 可得当这可红黑树的所有结点都为BLACK时(近似于完美二叉树形态),黑高为k但是高度此时最小即h = bh(x) 。 当高度最大时,即红黑相间 (近似于完美二叉树形态),此时 h = 2 * bh(x)。】
(2)一棵有n个内部结点的红黑树的高度至多为2lg(n+1)
【由于性质(1)所以 n >=2^( bh(x) ) - 1, 当 bh(x) = h / 2时,h最大,所以 n >= 2^(h/2)-1
取对数后为 2lg(n+1) 至少为 lg(n+1)/2(待验证)】
(3) 从某结点x 到其后代叶结点的所有简单路径中,最长的一条最多是最短一条的2倍
(4)在一棵有n个结点的红黑树中,RED:BLACK最大为2:1(红黑交替,并且最底层是RED)最小为0 (全为BLACK)
由(2)可以看出,被包装后的二叉搜索树——红黑树,高度最大为2lg(n+1),又因为,二叉搜索树的动态操作时间复杂度(除找第k大数外)都与高度成正比即0(lgn),所以红黑树在执行动态操作时期复杂度上限时刻保持着0(lgn)。

 

 

 

 

 

 

 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define RED (0)
#define BLACK (1)
typedef int elementType;
struct treeNode {
	struct treeNode* left;
	struct treeNode* right;
	struct treeNode* parent;
	elementType data;
	int color;
};
typedef struct treeNode* Tree;
struct treeNode* TN = NULL;  // 哨兵

 


问题二、如何去“包装”一棵二叉搜索树的动态操作变成红黑树呢?

 

 

红黑树的旋转

为了能在进行动态的删除插入等操作维护一棵二叉搜索树趋于红黑树,就要对REDBLACK结点进行相应的调整,其中就用到了红黑树的旋转。旋转分为左旋和右旋,并且这两者其过程基本类似。以左旋为例:

 



红黑树的旋转必须在不改变树中结点“顺序”的条件下进行,比如 图一 中序遍历为
α X β Y r 所以, 左旋后 的图二中序遍历也必须为 α X β Y r ,但是为了能保持红黑树的性质,要让X 和 Y 交换位置。所以过程应该为:先将 Y的左子树β 成为X的右子树,然后将 X 成为 Y的左子树。 同时在这个过程中也要对X Y 的 父母之间进行变化。

 

//左旋
static Tree Left_Rotate(Tree T, struct treeNode* x)
{
	struct treeNode* y = x->right; //将x的右儿子设置成y
	x->right = y->left;  // 将 Y的左子树β 成为X的右子树
	if (y->left != NULL) // 对β父母进行调整
	{
		y->left->parent = x;
	}

	y->parent = x->parent; //由于X变成Y,需要与红黑树的其他部分重新连接
	if (x->parent == TN)
	{
		T = y;
	}
	else
	{
		if (x == x->parent->left) x->parent->left = y;
		else                      x->parent->right = y;
	}

	y->left = x;  //将 X 成为 Y的左子树
	x->parent = y;//对 x的父母进行调整
	return T;
}

//右旋
static Tree Right_Rotate(Tree T, struct treeNode* Y)
{
	struct treeNode* x = Y->left;   //将Y的左儿子设置成x
	Y->left = x->right; //  将 x的右子树β 成为y的左子树
	if (x->right !&#
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值