红黑树
红黑树算是用的比较多,但是平时自己很少写的一种数据结构了,先看下介绍:
红黑树(Red Black Tree) 是一种自平衡二叉查找树,是在计算机科学中用到的一种数据结构,典型的用途是实现关联数组。
看~ 典型是用来实现关联数组,能想到什么数据结构呢?list map set
这些容器的底层都是红黑树来实现的。
红黑树和AVL树(平衡二叉查找树)
红黑树并不是完全平衡的一棵树,所以红黑树是在平均时间(经验)上为O(log n)的复杂度,包括插入,删除和查找。
红黑树规则
- 所有节点都分为红色和黑色两种颜色节点。
- 所有的叶子节点(外节点)都是黑色。
- 根节点是黑色。
- 所有的节点到它的叶子节点的路径的黑深度是相等的。
- 红色节点的两个孩子节点一定是黑色的。
这5条看起来很多,但其实很容易理解,这里最重要的是任意一个节点到它的叶子节点的路径的黑深度是相等的。它保证了树的平衡。而红色节点的孩子节点是黑色的则保证了树的黑色和红色节点的均衡。
红黑树查找
红黑树的查找很简单,左小右大的结构,相当于二分查找,和AVL树的查找是类似的,时间复杂度上面也说了平均为: log(n).
红黑树的插入和删除
这是红黑树最难的两个地方, 插入节点一定插入的位置是叶子,当插入的时候需要判断是否红黑树还满足上面5条性质,假如不满足要进行旋转操作。
为了保持黑深度的相等,插入的节点一定是红色节点
但是! 插入一个红色节点之后,可能会破坏红黑树的性质5. 所以插入之后判断是否满足。不满足的话旋转。
旋转有四种情况,虽然都是单旋转,但是每次旋转的步骤并不相同,因为画起来很麻烦,我直接找了书上的图片~
- 情况1
这个是除了插入直接符合外最简单的情况,就是插入节点的父节点是红色,祖父节点是黑色,则只用把父节点变到祖父节点的位置,并变为黑色,祖父节点变为父节点的右孩子。就可以了。
- 情况2
这种情况和第一种唯一不同的点在于孩子节点插入到了父亲节点的右节点,所以要先进行一次左旋转,一次右旋转。
(类似AVL树的双旋转)
- 情况3
这个和情况1一样,就是S不为NULL了,但这个是有限制的,可以看到P移动到G的位置了,P为红色,也就是说原RB树的G的父节点要是黑色,不然就是情况4了。
- 情况4
这个情况就是情况3的升级版本,就是说G的父节点还是红色,那么就要循环向上继续做,继续旋转,可能会遇到1 2 3的情况,就可以成功解决。
代码
我自己尝试写了一下红黑树的实现,Insert没有完全完成。以后慢慢更新这篇博客吧。
还是相对比较麻烦的。
//
// main.cpp
// Red_Black_Tree
//
// Created by Alps on 15/5/13.
// Copyright (c) 2015年 chen. All rights reserved.
//
#include <iostream>
#include <string>
using namespace std;
typedef bool rb_tree_color;
const rb_tree_color rb_tree_red = false; //红色为false
const rb_tree_color rb_tree_black = true; //黑色为true
struct rb_tree_node_base{
typedef rb_tree_color color_type;
typedef rb_tree_node_base* base_ptr;
color_type color;
base_ptr parent;
base_ptr left;
base_ptr right;
static base_ptr minnum(base_ptr T){
while(T->left != NULL){
T = T->left;
}
return T;
}
static base_ptr maxnum(base_ptr T){
while(T->right != NULL){
T = T->right;
}
return T;
}
};
struct rb_tree_node : public rb_tree_node_base{
typedef rb_tree_node* link_type;
int value_field;
};
class rb_tree{
public:
typedef rb_tree_node* link_type;
typedef size_t size_type;
typedef rb_tree_node_base* base_ptr;
link_type header;
size_type node_count;
link_type& root() const{
return (link_type&) header->parent;
}
link_type& leftmost() const{
return (link_type&) header->left;
}
link_type& rightmost() const{
return (link_type&) header->right;
}
//取极大值和极小值 用rb_tree_node自带的来实现
static link_type minnum(link_type T){
return (link_type)rb_tree_node::minnum(T);
}
static link_type maxnum(link_type T){
return (link_type)rb_tree_node::maxnum(T);
}
protected:
link_type get_node(){
return (link_type)malloc(sizeof(struct rb_tree_node));
}
static link_type& left(base_ptr x){
return (link_type&)(x->left);
}
static link_type& right(base_ptr x){
return (link_type&)(x->right);
}
static link_type& parent(base_ptr x){
return (link_type&)(x->parent);
}
private:
void init(){
header = get_node();
header->color = rb_tree_red;
root() = NULL;
leftmost() = header;
rightmost() = header;
}
public:
rb_tree():node_count(0){
init();
}
~rb_tree(){
// clear();
// put_node(header);
}
private:
link_type& insert_tree(base_ptr x, base_ptr y, const int v);
public:
link_type insert_equal(const int v){
link_type y = header;
link_type x = root();
while (x != 0) {
y = x;
x = (v > x->value_field ? left(x) : right(x));
}
return insert_tree(x, y, v);
}
pair<link_type, bool> insert_unique(const int v){
link_type y = header;
link_type x = root();
while (x != 0) {
y = x;
x = v > x->value_field ? right(x) : left(x);
}
link_type z = y;
if (v < y->value_field) {
if (y->left == NULL) {
return make_pair(_insert(x, y, v), true);
}else{
z = (link_type)z->parent; //不太懂
}
}
return make_pair(y, false);
}
link_type _insert(base_ptr x, base_ptr y, const int v){
return (link_type)x;
}
};
int main(int argc, const char * argv[]) {
// insert code here...
std::cout << "Hello, World!\n";
return 0;
}
写这个代码的时候,我参考了源码,insert部分还没有写完,主要是不是模板,在使用迭代器的时候有点麻烦。
红黑树最重要的是知道运行院里,知道底层的一些操作,和性能。