您的位置:首页 > 其它

红黑树的插入与删除算法

2016-10-29 22:43 549 查看
本文地址:http://blog.csdn.net/freeelinux/article/details/52966934

一:旋转操作

将几种情况之前先看一下旋转操作。

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息