红黑树的插入与删除算法

本文地址: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[N] = {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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值