红黑树的插入与删除算法
2016-10-29 22:43
549 查看
本文地址:http://blog.csdn.net/freeelinux/article/details/52966934
1.rotate_left
代码如下:
颜色在外部修改。
2.rotate_right
3.rotate_left_right
从这幅图可以看出,起始没有左右,右左,只是左旋和右旋的组合而已。
4.rotete_right
不再介绍。
插入算法有四种情况,不过主要分两类。
把x结点的父节点的兄弟称为叔。
1.黑叔
如果是黑叔,那就参考上面那几幅图进行相应的旋转。
2.红叔
如果是红叔,那就是下面这样子,只需要把颜色改一下,检查祖父节点pp的颜色,可能需要继续向上调整。
另外一种:
三:删除算法
删除算法只画了一张图,具体可以去参考算法导论。
四:代码如下
.h:
.cpp
测试用例:
一:旋转操作
将几种情况之前先看一下旋转操作。1.rotate_left
代码如下:
void rb_tree::rotate_left(node_type* x) //x is the rotate point { assert(x != nil_); node_type *y = x->right_; x->right_ = y->left_; if(y->left_ != nil_) y->left_->parent_ = x; y->parent_ = x->parent_; //notice who's father changed if(x == root_) root_ = y; else if(x == x->parent_->left_) x->parent_->left_ = y; else x->parent_->right_ = y; y->left_ = x; x->parent_ = y; }
颜色在外部修改。
2.rotate_right
void rb_tree::rotate_right(node_type* x) //x is the rotate point { assert(x != nil_); node_type *y = x->left_; x->left_ = y->right_; if(y->right_ != nil_) y->right_->parent_ = x; y->parent_ = x->parent_; //make self point to father if(x == root_) root_ = y; else if(x == x->parent_->left_) //make the father point to self x->parent_->left_ = y; else x->parent_->right_ = y; y->right_ = x; x->parent_ = y; }
3.rotate_left_right
从这幅图可以看出,起始没有左右,右左,只是左旋和右旋的组合而已。
4.rotete_right
不再介绍。
二:插入算法
插入算法解决的是红红问题,不能有两个红结点相邻。插入算法有四种情况,不过主要分两类。
把x结点的父节点的兄弟称为叔。
1.黑叔
如果是黑叔,那就参考上面那几幅图进行相应的旋转。
2.红叔
如果是红叔,那就是下面这样子,只需要把颜色改一下,检查祖父节点pp的颜色,可能需要继续向上调整。
另外一种:
三:删除算法
删除算法只画了一张图,具体可以去参考算法导论。
四:代码如下
.h:
#ifndef _RB_TREE_H #define _RB_TREE_H #include <iostream> #include <stdio.h> #include <assert.h> #define _DEBUG_ typedef enum {RED, BLACK}color_type; typedef int elem_type; class rb_tree; struct rb_tree_node{ friend class rb_tree; public: explicit rb_tree_node(elem_type data=-1, color_type color=RED, rb_tree_node* left=NULL, rb_tree_node* right=NULL, rb_tree_node* parent=NULL) : data_(data), color_(color), left_(left), right_(right), parent_(parent) {} ~rb_tree_node(){ left_ = right_ = parent_ = NULL; } private: elem_type data_; color_type color_; rb_tree_node* left_; rb_tree_node* right_; rb_tree_node* parent_; }; typedef rb_tree_node node_type; class rb_tree { public: rb_tree(){ nil_ = new(std::nothrow) node_type(-1, BLACK); //for any empty node assert(nil_ != NULL); root_ = nil_; nil_->left_ = nil_; //nil指向自己,把哨兵结点当作黑结点 nil_->right_ = nil_; nil_->parent_ = nil_; } ~rb_tree(){ destroy(root_); delete nil_; } public: #ifdef _DEBUG_ void inorder_traverse() const{ inorder_traverse(root_); } void inorder_traverse(node_type* const &) const; #endif bool insert(const elem_type& key); bool remove(const elem_type& key); //void set_compare_method(void (*compare)(const void*, const void*)); private: void insert_fixup(node_type *x); void delete_fixup(node_type*& x); void rotate_left(node_type* p); void rotate_right(node_type *p); node_type* locate(const elem_type& key) const; node_type* locate_detail(node_type*&, const elem_type& key) const; node_type* apply_node(const elem_type& val=-1, //申请结点 color_type color = RED); void destroy(node_type* t); private: //void (*compare_)(const void *, const void*); node_type* nil_; //使用这个充当哨兵结点,root->nil,所有指向空的都指向该节点 //stl中nil的left和right指向leftmost和rightmost,我这里nil指向自己 node_type* root_; }; #endif
.cpp
#include "rb_tree.h"
#if 0
void rb_tree::set_compare_method(void (*compare)(const void*, const void*)) //暂未使用
{
assert(compare != NULL);
compare_ = compare;
}
#endif
void rb_tree::destroy(node_type *t)
{
if(t != nil_){
if(t->left_ != nil_)
destroy(t->left_);
else if(t->right_ != nil_)
destroy(t->right_);
delete(t);
}
}
node_type* rb_tree::apply_node(const elem_type& val, color_type color)
{
node_type* tmp = new(std::nothrow) node_type(val, RED, nil_, nil_, nil_); //no throw
assert(tmp != NULL); //申请的所有新结点默认红结点,指向哨兵结点
return tmp;
}
bool rb_tree::insert(const elem_type& key)
{
#ifdef _DEBUG_
fprintf(stdout, "insert %d\n", key);
#endif
node_type *iter = root_;
node_type *parent = nil_;
while(iter != nil_){ //先找插入位置
parent = iter;
if(key < iter->data_)
iter = iter->left_;
else if(key > iter->data_)
iter = iter->right_;
else
return false;
}
iter = apply_node(key);
iter->parent_ = parent;
if(parent == nil_){ //iter->parent == nil, shows this is the root_ node
iter->color_ = BLACK; //it's worth notice that we put parent == nil_ first
root_ = iter; //will not affect the efficiency, because the nil_->data_ = -1,
return true; //so that we can not compare > or < first;
} //weeyanghuang@gmail.com
else if(parent->data_ > key)
parent->left_ = iter;
else
parent->right_ = iter;
if(iter->parent_->color_ == BLACK)
return true;
else
insert_fixup(iter);
return true;
}
void rb_tree::insert_fixup(node_type* x) //x:insert node, p:x->parent pp:x->parent->parent s:uncle node
{
assert(x != nil_);
while(x != root_ && x->parent_->color_ == RED){ //RED-RED,插入解决的是红红问题,所以只要为红,一直向上检查
if(x->parent_ == x->parent_->parent_->left_){ //the father is grandfather's left child
node_type* s = x->parent_->parent_->right_;
if(s && s->color_ == RED){ //s->color == RED 红叔时只需改变颜色并向上检查即可
s->color_ = BLACK;
x->parent_->color_ = BLACK;
x->parent_->parent_->color_ = RED; //modify two BLACK one red
x = x->parent_->parent_;
}
else{ //s->color == BLACK 黑叔时可能有左旋,或有左旋,和下面镜像关系
if(x == x->parent_->right_){
x = x->parent_;
rotate_left(x);
}
x->parent_->color_ = BLACK;
x->parent_->parent_->color_ = RED;
rotate_right(x->parent_->parent_);
}
}
else{ //the father is grandfather's right child //镜像
node_type* s = x->parent_->parent_->left_;
if(s && s->color_ == RED){
s->color_ = BLACK;
x->parent_->color_ = BLACK;
x->parent_->parent_->color_ = RED;
x = x->parent_->parent_;
}
else{
if(x == x->parent_->left_){
x = x->parent_;
rotate_right(x);
}
x->parent_->color_ = BLACK;
x->parent_->parent_->color_ = RED;
rotate_left(x->parent_->parent_);
}
}
}
root_->color_ = BLACK;
}
void rb_tree::rotate_right(node_type* x) //x is the rotate point //这里的x都是旋转点
{
assert(x != nil_);
node_type *y = x->left_;
x->left_ = y->right_;
if(y->right_ != nil_)
y->right_->parent_ = x;
y->parent_ = x->parent_; //make self point to father
if(x == root_)
root_ = y;
else if(x == x->parent_->left_) //make the father point to self
x->parent_->left_ = y;
else
x->parent_->right_ = y;
y->right_ = x;
x->parent_ = y;
}
void rb_tree::rotate_left(node_type* x) //x is the rotate point { assert(x != nil_); node_type *y = x->right_; x->right_ = y->left_; if(y->left_ != nil_) y->left_->parent_ = x; y->parent_ = x->parent_; //notice who's father changed if(x == root_) root_ = y; else if(x == x->parent_->left_) x->parent_->left_ = y; else x->parent_->right_ = y; y->left_ = x; x->parent_ = y; }
node_type* rb_tree::locate(const elem_type& key) const //查找
{
if(root_ == nil_)
return nil_;
if(root_->data_ == key)
return root_;
node_type* t = root_;
return locate_detail(t, key);
}
node_type* rb_tree::locate_detail(node_type*& t, const elem_type& key) const
{
if(t == nil_)
return nil_;
if(t->data_ == key)
return t;
node_type *found = nil_;
if(key < t->data_)
found = locate_detail(t->left_, key);
return (found == nil_ ? locate_detail(t->right_, key) : found);
}
bool rb_tree::remove(const elem_type& key) //z:delete y:delete actually x:y->child x_parent:x->parent
{
node_type* z = locate(key);
assert(z != nil_);
node_type* y = z;
node_type* x = nil_; //我在这个函数没有用x_parent_,因为我直接用哨兵节点的nil->parent指向它父节点
if(y->left_ == nil_)
x = y->right_;
else{
if(y->right_ == nil_)
x = y->left_;
else{
y = z->right_;
while(y->left_ != nil_)
y = y->left_;
x = y->right_;
/*2016.11.3 修改*/
x->parent_ = y; //这是时隔三天发现的bug,既然我们后面要用哨兵节点的parent_,那么就要保证哨兵节点的parent_指向正确的父节点
//否则在下个函数中node_type* x_parent = x->parent_; 可能会指向垃圾地址
//由于stl的红黑书删除算法delete和delete_fixup在同一函数中,所以它直接采用x_parent第三方来保存父节点指针
//那我写了一个函数remove_fixup,为了不用再传递一个参数,并且利用上我们哨兵节点的特性,只需要在第一个函数中
//时刻保持x结点父节点的正确指向即可
}
}
if(y != z){
y->left_ = z->left_;
/*2016.11.3*/
//if(z->left_ != nil_) //同样,像这种是不必要判断的,因为我们哨兵节点本身就是结点,具有parent_指针域
z->left_->parent_ = y;
if(y != z->right_){
x->parent_ = y->parent_; //无需判断x是否为nil,直接让其parent_指向即可,因为它本身就是一个节点
y->parent_->left_ = x;
y->right_ = z->right_;
z->right_->parent_ = y;
}
y->parent_ = z->parent_;
if(root_ == z)
root_ = y;
else if(z == z->parent_->left_)
z->parent_->left_ = y;
else
z->parent_->right_ = y;
std::swap(z->color_, y->color_); //don't forget swap color, move the un_balance to actually deleted
y = z; //y now points to node to be actually deleted
}
else{
x->parent_ = z->parent_; //无需判断
if(root_ == z)
root_ = x;
else if(z == z->parent_->left_)
z->parent_->left_ = x;
else
z->parent_->right_ = x;
}
if(y->color_ != RED)
delete_fixup(x); //delete_fixup函数参数是实际删除点y结点的孩子节点,这是可以为nil结点的
<span style="white-space:pre"> </span> //毕竟我们的处理思想就是哨兵结点也是结点,它是一个黑结点!
delete(z);
}
void rb_tree::delete_fixup(node_type*& x)
{
node_type* x_parent = x->parent_; //上面利用nil结点保存parent_,在这里就可以用上
while(x != root_ && (x == nil_ || x->color_ == BLACK)){ //BLACK-BLACK
if(x == x->parent_->left_){
node_type* s = x_parent->right_;
if(s->color_ == RED){ //case 1 , red uncle
x_parent->color_ = RED; //case 1
s->color_ = BLACK; //case 1
rotate_left(x_parent); //case 1
s = x_parent->right_; //case 1
}
else{
if( (s->left_ == nil_ || s->left_->color_ == BLACK) //case 2
&& (s->right_ == nil_ || s->right_->color_ == BLACK)){ //case 2
s->color_ = RED; //case 2
x = x_parent; //case 2 ,if x_parent->color_ == RED, break, make it black after while
x_parent = x_parent->parent_; //case 2
}
else{
if(s->right_ == nil_ || s->right_->color_ == BLACK){ //case 3
s->left_->color_ = BLACK; //case 3, s->left_ might be nil_
s->color_ = RED; //case 3
rotate_right(s); //case 3
s = x_parent->right_; //case 3
}
s->color_ = x_parent->color_; //case 4, get father's color
x_parent->color_ = BLACK; //case 4
s->right_->color_ = BLACK; //case 4, s->right_ might be nil_
rotate_left(x_parent); //case 4
break;
}
}
}
else{ //the following is the mirror
node_type* s = x_parent->left_;
if(s->color_ == RED){
x_parent->color_ = RED;
s->color_ = BLACK;
rotate_right(x_parent);
s = x_parent->left_;
}
else{
if( (s->right_ == nil_ || s->right_->color_ == BLACK)
&& (s->left_ == nil_ || s->left_->color_ == BLACK)){
s->color_ = RED;
x = x_parent;
x_parent = x_parent->parent_;
}
else{
if(s->left_ == nil_ || s->left_->color_ == BLACK){
s->right_->color_ = BLACK;
s->color_ = RED;
rotate_left(s);
s = x_parent->left_;
}
s->color_ = x_parent->color_;
x_parent->color_ = BLACK;
s->left_->color_ = BLACK;
rotate_right(x_parent);
break;
}
}
}
}
x->color_ = BLACK;
}
#ifdef _DEBUG_
void rb_tree::inorder_traverse(node_type* const &t) const
{
if(t != nil_){
if(t->left_ != nil_)
inorder_traverse(t->left_);
std::cout<<t->data_<<std::endl;
if(t->right_ != nil_)
inorder_traverse(t->right_);
}
}
#endif
测试用例:
#include "rb_tree.h" #include <iostream> using namespace std; //void compare( int main() { rb_tree rbt; /////////////////////////////////////////////////////////////////// // s color is BLACK /* //test for rotate right rbt.insert(10); rbt.insert(8); rbt.insert(5); */ /* //test for rotate left_right rbt.insert(10); rbt.insert(7); rbt.insert(9); */ //////////////////////////////////////////////////////////////////// //s color is RED //no rotate !!!! /* //test for left_right rbt.insert(10); rbt.insert(11); rbt.insert(6); rbt.insert(9); */ /* //test for right rbt.insert(10); rbt.insert(11); rbt.insert(9); rbt.insert(7); */ //random test const int N = 10; int array = {1,9,14,3,7,23, 12, 8, 4, 6}; for(int i=0; i<N; ++i) rbt.insert(*(array+i)); rbt.inorder_traverse(); //test for locate for(int i=0; i<N; ++i){ sleep(1); rbt.remove(*(array+i)); rbt.inorder_traverse(); } /* rbt.remove(3); rbt.inorder_traverse(); */ return 0; }
相关文章推荐
- 【算法】红黑树的讲解及插入删除算法实现原理
- 红黑树的插入删除算法的实现(java描述)
- 解析《算法导论》中红黑树的插入和删除算法
- 经典算法:红黑树的C语言实现 ( 插入 、删除 )
- 红黑树插入与删除 算法实现+代码(一)
- [算法导论]红黑树实现(插入和删除) @ Python
- 红黑树插入与删除 算法实现+代码(二)
- 红黑树插入删除归类
- 堆排序,插入,删除,调整算法(大顶堆)
- 顺序表的定义、初始化、及插入、删除、查询操作,将算法转化成具体的代码
- 红黑树插入和删除结点的全程演示
- 算法练习五 红黑树下 节点删除
- 红黑树实现-插入和删除
- 应用数据结构(一)线性表节点的插入和删除算法
- 一步一步写算法(之链表的删除与插入)
- 双向链表的插入和删除算法
- 堆排序,插入,删除,调整算法(大顶堆)
- 数组 算法没有插入删除,只有存取和修改
- C++ STL标准容器插入删除算法的复杂度(来源flyhorse)
- 红黑树从头至尾插入和删除结点的全程演示图