《算法导论》学习笔记之Chapter13红黑树

第13章 红黑树

红黑树是一种平衡搜索树中的一种,他可以保证在最坏情况下基本动态集合操作时间复杂度为O(logn)。所以,在学习红黑树之前,我需要先去调研一下平衡树

先看一下平衡树的定义:平衡树,即平衡二叉树(Balanced Binary Tree):它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。平衡二叉树的常用实现方法有红黑树AVL(平衡查找树)替罪羊树Treap伸展树等。 最小二叉平衡树的节点的公式为: F(n)=F(n-1)+F(n-2)+1 ,这个类似于一个递归的数列,可以参考Fibonacci数列,1是根节点,F(n-1)是左子树的节点数量,F(n-2)是右子树的节点数量。

下面这段介绍很生动:对一棵查找树(search tree)进行查询/新增/删除 等动作, 所花的时间与树的高度h 成比例, 并不与树的容量 n 成比例。如果可以让树维持矮矮胖胖的好身材, 也就是让h维持在O(lg n)左右, 完成上述工作就很省时间。能够一直维持好身材, 不因新增删除而长歪的搜寻树, 叫做balanced search tree(平衡树)。所以,可以看出,构造平衡树的动机就在于:对于普通二叉搜索树,虽然最好情况和一般情况都趋近于O(lg n),但是最坏情况非常糟糕,会存在树的高度h=n的畸形情况,此时树的性能非常糟糕。

下面介绍两种常见的平衡树算法基本概念(百度得来。。。):

红黑树:

红黑树的平衡是在插入和删除的过程中取得的。对一个要插入的数据项,插入程序要检查不会破坏树一定的特征。如果破坏了,程序就会进行纠正,根据需要更改树的结构。通过维持树的特征,保持了树的平衡。
红黑树有两个特征:
(1) 节点都有颜色
(2) 在插入和删除过程中,要遵循保持这些颜色的不同排列的规则。
红黑规则:
1. 每一个节点不是红色的就是黑色的
2. 根总是黑色的,每个叶结点(null)是黑色的
3. 如果节点是红色的,则它的子节点必须是黑色的(反之不一定成立
4. 从根到叶节点或空子节点的每条路径,必须包含相同数目的黑色节点
(空子节点是指非叶节点可以接子节点的位置。换句话说,就是一个有右子节点的节点可能接左子节点的位置,或是有左子节点的节点可能接右子节点的位置)
AVL树:

AVL树,它或者是一颗空二叉树,或者是具有下列性质的二叉树:
(1) 其根的左右子树高度之差的绝对值不能超过1;
(2) 其根的左右子树都是二叉平衡树。
AVL树查找的时间复杂度为O(logN),因为树一定是平衡的。但是由于插入或删除一个节点时需要扫描两趟树,依次向下查找插入点,依次向上平衡树,AVL树不如红黑树效率高,也不如红黑树常用。

了解了基本概念和特性,下面开始介绍红黑树了。

红黑树通过对任何一条从根到叶子的简单路径上各个结点的颜色进行约束,确保没有一条路径会比其他路径长处2倍,因而近似于平衡的。

书中每个及诶单包含5个属性:color,key,left,right,p。如果一个节点没有子节点或父结点,则该节点相应指针属性为null。把这些Null视为指向二叉搜索树的叶结点(外部结点)的指针,把带有关键字的结点视为数的内部节点。

红黑树这种有一个概念:哨兵,代表Null。对于一颗红黑树T,哨兵T.null是一个与树中普通节点具有相同属性的对象。她的color属性为black,其他属性任意。所有指向null的指针都用指向哨兵T.null的指针替换。

从某个节点x出发(不含该节点)到达一个叶结点的任意一条简单路径上的黑色结点个数成为该节点的黑高,记为bh(x)。由于上述性质 ,可以得出红黑树的黑高为其根结点的黑高。

一颗有n个内部节点的红黑树的高度至多为2lg(n+1),即 h <= 2lg(n+1)。所以红黑树是一种好的搜索树。

从性质3还可得出,从根节点到叶结点(不包括根节点)的任何一条简单路径上都至少有一半的结点为黑色。因此,根的黑高至少为h/2(h为树高)。于是有  n >= 2.^(h/2) - 1.

综上所述,一颗红黑树上的查找删除等操作时间复杂度都在O(lgn)范围内。

红黑树保持平衡的操作就是旋转操作:左旋和右旋,下面是代码实现:

public void leftRotate(RedBlackTree tree, RBNode x) {
		RBNode y = x.right;// 找到要旋转结点的右子节点
		x.right = y.left;// 让y节点的左子节点旋转到x的右子节点处,注意:此处仍符合搜索树的大小关系
		if (y.left != tree.Nil) {//如果y的左子节点不为空,修改其父结点为x
			y.left.p = x;
		}
		y.p = x.p;//修改y结点的父结点为x的父结点
		if (x.p == tree.Nil) {// 如果x是根结点,则y变为根结点
			tree.root = y;
		} else if (x == x.p.left) {// 如果x是其父结点的左子节点,则令x父结点的左结点为y
			x.p.left = y;
		} else {// 如果x是其父结点的右子节点,则令x父结点的右结点为y
			x.p.right = y;
		}
		y.left = x;//旋转x为y的左结点
		x.p = y;//修改x的父结点为y
	}

	public void rightRotate(RedBlackTree tree, RBNode y) {
		RBNode x = y.left;
		y.left = x.right;
		if (x.right != tree.Nil) {
			x.right.p = y;
		}
		x.p = y.p;
		if (y.p == tree.Nil) {// 如果y是根结点
			tree.root = x;
		} else if (y == y.p.left) {// 如果y是其父结点的左子节点
			y.p.left = x;
		} else {// 如果y是其父结点的右子节点
			y.p.right = x;
		}
		x.right = y;
		y.p = x;
	}

下面附加一张旋转图还辅助理解:



下面就介绍红黑树中的插入操作:



















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值