您的位置:首页 > 编程语言

stl map底层之红黑树插入步骤详解与代码实现

2016-11-03 16:32 666 查看
本篇文章并没有详细的讲解红黑树各方面的知识,只是以图形的方式对红黑树插入节点需要进行调整的过程进行的解释。

最近在看stl源码剖析,看到map底层红黑树的实现。为了加深对于红黑树的理解就自己动手写了红黑树插入的实现。关于红黑树插入节点后破坏红黑树性质的几种情况,可以在网上搜到很多相关的信息。下面用图说明插入新节点时红黑树所做的调整。插入的序列分别是30,40,50,20,35,10,11。

首先是插入30,由于现在红黑树是一棵空,所以直接将30作为根节点,并将根节点颜色染成黑色即可。

一、插入40,如下图所示。由于此时并没有破坏红黑树的性质,所以此时插入成功。



图1:插入40

二、插入50,插入节点50后,50及其父节点都为红色,由于此时40没有兄弟节点。此时将父节点变黑,祖父节点变红,以祖父节点为根进行左旋。调整后如图2-2所示





图2-1:插入节点50 图2-2:插入节点50调整后

三、插入20,插入节点20后,其父节点30及叔节点50都是红色节点。解决方法是将父节点及叔节点变黑,祖父节点变红。祖父节点变成新的当前节点重新进行算法。由于40是根节点,所以将根节点变黑。调整后如图3-2所示,此时满足红黑树的全部性质。





图3-1:插入节点20 图3-2:插入节点20调整后

四、插入节点35,如图4所示,由于此时并未破坏红黑树的任何性质。不需要进行调整算法。



图4:插入节点35

五、插入节点10,此时10的父节点20及其叔节点35都是红色。将20及35节点变黑,祖父节点30变红。30作为新的当前节点。由于30的父节点40是黑色。所以调整算法结束。调整后如图5-2所示



图5-1:插入节点10



图5-2:插入节点10调整后

六、插入节点11,如图6-1所示,由于11的父节点10是红色节点,并且11是10的右子节点。所以首先以10节点为根节点进行左旋,旋转后其的红黑树如图6-2所示。此时节点10的父节点11为红色,并且10是11节点的左子节点;此时将父节点11变黑,祖父节点20变红,以祖父节点20为根节点进行右旋。旋转后如图6-3所示。



图6-1:插入节点11



图6-2:10为根节点进行左旋后



图6-3:插入节点调整后的红黑树

下面附上只实现了插入功能的红黑树源码

rbtree.h

[cpp] view
plain copy







#include <iostream>

#include <queue>

using namespace std;

static int _rb_black_node = 0;

static int _rb_red_node = 1;

template<typename T>

struct RBNode

{

RBNode():left(NULL),right(NULL),parent(NULL),val(T()),color(_rb_red_node){}

RBNode(const T &v1):left(NULL),right(NULL),parent(NULL),val(v1),color(_rb_red_node){}

RBNode *left;

RBNode *right;

RBNode *parent;

int color;

T val;

};

template<typename T>

class RBTree

{

public:

RBTree():root(NULL){}

~RBTree()

{

if(root)

{

Destroy(root);

}

}

void print();

void Search(const T &v1, RBNode<T> *&node);

bool InsertUnique(const T &v1);

void DeleteValue(const T &v1);

void Destroy(RBNode<T> *p);

void InsertReBalance(RBNode<T> *node);

RBNode<T>* _rbtree_rotate_left(RBNode<T> *node);

RBNode<T>* _rbtree_rotate_right(RBNode<T> *node);

private:

RBNode<T> *root;

};

/*

*

* 打印红黑树的节点信息

*

*/

template<typename T>

void RBTree<T>::print()

{

RBNode<T> *p;

queue<RBNode<T> *> Q;

Q.push(root);

while(!Q.empty())

{

p = Q.front();

Q.pop();

cout<<"节点: "<<p->val<<" ";

if(p->left)

{

cout<<"left:"<<p->left->val<<"->color:"<<p->left->color<<" ";

Q.push(p->left);

}

if(p->right)

{

cout<<"right:"<<p->right->val<<"->color:"<<p->right->color<<" ";

Q.push(p->right);

}

cout<<endl<<endl;

}

}

/*

*

* 搜索v1在红黑树中出现的位置,如果v1在红黑树中则node节点为

* 值为v1所在红黑树中的节点。

* 否则node节点为如果将v1插入到红黑树中的父节点

*

*/

template<typename T>

void RBTree<T>::Search(const T &v1,RBNode<T> *&node)

{

RBNode<T> *p = root;

node = NULL;

while(p)

{

if(p->val == v1)

{

node = p;

break;

}

else if(p->val < v1)

{

node = p;

p = p->right;

}

else

{

node = p;

p = p->left;

}

}

}

template<typename T>

bool RBTree<T>::InsertUnique(const T &v1)

{

RBNode<T> *parent = NULL;

RBNode<T> *newNode = new RBNode<T>(v1);

Search(v1, parent);

if(parent == NULL)

{//红黑树为空,当前插入的节点为根节点。插入后将根颜色变为黑

root = newNode;

root->color = _rb_black_node;

return true;

}

if(parent->val == v1)//v1已经存在红黑树中。不再插入

return false;

if(v1 < parent->val)

{

parent->left = newNode;

}

else

{

parent->right = newNode;

}

newNode->parent = parent;

InsertReBalance(newNode);

return true;

}

/*

*

* 插入节点后进行调整,

* 使所有节点满足红黑树的性质

*

*/

template<typename T>

void RBTree<T>::InsertReBalance(RBNode<T> *node)

{

RBNode<T> *parent = node->parent;

RBNode<T> *grandParent = NULL;

while(parent && parent->color==_rb_red_node)

{

grandParent = parent->parent;

if(parent == grandParent->left)

{//父节点为祖父节点的左儿子

RBNode<T> *uncle = grandParent->right;

if(uncle && uncle->color == _rb_red_node)

{//情形1 父节点与叔节点都为红

//解决方法父与叔变黑,祖父变黑。祖父变为新的当前节点重新进入算法

parent->color = _rb_black_node;

uncle->color = _rb_black_node;

grandParent->color = _rb_red_node;

node = grandParent;

parent = grandParent->parent;

}

else

{

if(node == parent->right)

{//情形2,叔为黑,当前节点为其父节点的右子节点

//解决方法:以父节点为根进行左旋

//操作后将转换为情形3

node = _rbtree_rotate_left(parent);

parent = node->parent;

grandParent = parent->parent;

}

//情形3父为红,当前节点为父节点的左子节点

//解决方法:父节点变黑,祖父节点变红,以

//祖父节点为根节点进行右旋

parent->color = _rb_black_node;

grandParent->color = _rb_red_node;

_rbtree_rotate_right(grandParent);

}

}

else

{//父节点为祖父节点的右子节点,情况与上面相同

RBNode<T> *uncle = grandParent->left;

if(uncle && uncle->color == _rb_red_node)

{

uncle->color = _rb_black_node;

parent->color = _rb_black_node;

grandParent->color = _rb_red_node;

node = grandParent;

parent = node->parent;

}

else

{

if(node == parent->left)

{

node = _rbtree_rotate_right(parent);

parent = node->parent;

grandParent = parent->parent;

}

parent->color = _rb_black_node;

grandParent->color = _rb_red_node;

_rbtree_rotate_left(grandParent);

}

}

}

root->color = _rb_black_node;

}

/*

*

* 左旋

*

*/

template<typename T>

RBNode<T> *RBTree<T>::_rbtree_rotate_left(RBNode<T> *x)

{

RBNode<T> *y = x->right;

if(y == NULL)

{

return x;

}

//x的右节点为y的左节点

x->right = y->left;

if(y->left)//如果y的左节点存在,其父节点为y

y->left->parent = x;

if(root == x)

{//x为root,旋转后y为新的root根节点

root = y;

}

else

{

if(x == x->parent->left)

{//如果x为其父节点的左子节点。

//x的父节点的新左子节点为y

x->parent->left = y;

}

else

{

x->parent->right = y;

}

//y的父节点为x的父节点

y->parent = x->parent;

}

//y的左子节点为x

y->left = x;

//x的父节点为y

x->parent = y;

return x;

}

/*

*

* 右旋

* 分析其逻辑与左旋代码类似

*

*/

template<typename T>

RBNode<T>* RBTree<T>::_rbtree_rotate_right(RBNode<T> *x)

{

RBNode<T> *y = x->left;

if(y == NULL)

{

return x;

}

x->left = y->right;

if(y->right)

y->right->parent = x;

if(root == x)

{

root = y;

}

else

{

if(x == x->parent->left)

{

x->parent->left = y;

}

else

{

x->parent->right = y;

}

y->parent = x->parent;

}

y->right = x;

x->parent = y;

return x;

}

/*

*

* 销毁整棵红黑树

*

*/

template<typename T>

void RBTree<T>::Destroy(RBNode<T> *p)

{

if(p->left)

{

Destroy(p->left);

}

if(p->right)

{

Destroy(p->right);

}

delete p;

}

插入节点的程序:

[cpp] view
plain copy







#include "rbtree.h"

#include <iostream>

using namespace std;

int main()

{

RBTree<int> obj;

obj.InsertUnique(30);

obj.InsertUnique(40);

obj.InsertUnique(50);

obj.InsertUnique(20);

obj.InsertUnique(35);

obj.InsertUnique(10);

obj.InsertUnique(11);

obj.print();

return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: