本系列文章主要介绍常用的算法和数据结构的知识,记录的是《Algorithms I/II》课程的内容,采用的是“算法(第4版)”这本红宝书作为学习教材的,语言是java。这本书的名气我不用多说吧?豆瓣评分9.4,我自己也认为是极好的学习算法的书籍。
通过这系列文章,可以加深对数据结构和基本算法的理解(个人认为比学校讲的清晰多了),并加深对java的理解。
红黑树是一种简单的实现2-3树的数据结构,它方便的把我们之前实现的二叉搜索树改造成了一棵2-3树。它的核心思想是用一条左倾链(红链)作为“胶水”把二叉树的两个节点给粘起来,形成一个3节点。
把红链看成水平的,看是不是和2-3树就一样了
BST改造成红黑树有一些约定:
这样做的好处是什么?就是之前写的代码很多基本可以不用改就可以直接用(比如get,floor,ceiling操作,因为这些操作是不需要考虑红黑链的)
红黑树表示只用在BST中加入一个用来表明链的颜色的变量就行了。默认空链是黑色,我们把颜色加在node节点的属性中,通过查找孩子的node节点颜色,我们就知道指向这个节点的链的颜色了。
private static final boolean RED = true;
private static final boolean BLACK = false;
private class Node
{
Key key;
Value val;
Node left, right;
boolean color;
// color of parent link
}
private boolean isRed(Node x)
{
if (x == null) return false;
return x.color == RED;
}
这个操作用来修正因任何情况导致红链出现在右边的情况。操作主要步骤:
public Node rotateLeft(Node h)
{
assert isRed(h.right);
Node x = h.right;
h.right = x.left; //step 1
x.left = h; //step 2
x.color = h.color;
h.color = RED;
return x; //setp 3
}
和左旋操作差不多,只是方向变了
public Node rotateRight(Node h)
{
assert isRed(h.left);
Node x = h.left;
h.left = x.right; //step 1
x.right = h; //step 2
x.color = h.color;
h.color = RED;
return x; //setp 3
}
操作实现也比较简单,因为4节点的实现还是用的二叉树,我们只用把链的颜色改变就行了。
private void flipColors(Node h)
{
assert !isRed(h);
assert isRed(h.left);
assert isRed(h.right);
h.color = RED;
h.left.color = h.right.color = BLACK;
}
其实所有的插入操作,可以归结为下面三种:
private Node put(Node h, Key key, Value val)
{
/******原插入代码*******/
if (h == null)
return new Node(key, val, RED);
int cmp = key.compareTo(h.key);
if (cmp < 0) {
h.left = put(h.left, key, val);
} else if (cmp > 0) {
h.right = put(h.right, key, val);
} else if (cmp == 0) {
h.val = val;
}
h.count = 1 + size(h.left) + size(h.right);
/******情形1*******/
if (isRed(h.right) && !isRed(h.left))
h = rotateLeft(h);
/******情形2*******/
if (isRed(h.left) && isRed(h.left.left))
h = rotateRight(h);
/******情形3*******/
if (isRed(h.left) && isRed(h.right))
flipColors(h);
return h;
}
讲了这么多,我们来看看一棵红黑树到底如何构造出来的吧,通过通话来加深理解。
所有基于红黑树的符号表实现都保证操作的运行时间为对数级别!
因为,不论插入的顺序如何,红黑树都几乎是完美平衡的
不管是在随机情况下
还是在最坏的情况下,红黑树的深度也不会超过2logN
红黑树更吸引人的一点在于,基本除了put和delete算法比较复杂,其他的代码,都可以直接使用二叉树的代码。