红黑树(Red Black Tree) 是一种自平衡二叉查找树,是在计算机科学中用到的一种数据结构,典型的用途是实现关联数组。
它是在1972年由Rudolf Bayer发明的,当时被称为平衡二叉B树(symmetric binary B-trees)。后来,在1978年被 Leo J. Guibas 和 Robert Sedgewick 修改为如今的“红黑树”。
红黑树和AVL树类似,都是在进行插入和删除操作时通过特定操作保持二叉查找树的平衡,从而获得较高的查找性能。
它虽然是复杂的,但它的最坏情况运行时间也是非常良好的,并且在实践中是高效的: 它可以在O(log n)时间内做查找,插入和删除,这里的n 是树中元素的数目。
好了废话不多说,直接上代码,这儿是一篇详细介绍插入删除的文章
github地址:这里
1 #ifndef _RBTREE_H
2 #define _RBTREE_H
3
4 #include<iostream>
5 #include<stdlib.h>
6 #include<assert.h>
7 using namespace std;
8
9 enum COLOR{RED = 0,BLACK};
10
11 template<class T>
12 class RBTree;
13
14 template<class T>
15 class RBTreeNode //红黑树结点类
16 {
17 friend class RBTree<T>;
18 private:
19 T data; //数据域
20 COLOR color; //颜色
21 RBTreeNode<T> *parent; //父结点
22 RBTreeNode<T> *leftChild,*rightChild; //左右子女指针
23 public:
24 RBTreeNode():data(T(),color(RED),parent(NULL),leftChild(NULL),rightChild(NULL)) //无参构造函数
25 {}
26 RBTreeNode(T d,COLOR c = RED,RBTreeNode<T> *pr = NULL,RBTreeNode<T> *left = NULL,RBTreeNode<T> *ri ght = NULL):data(d),color(c),parent(pr),leftChild(left),rightChild(right) //带参构造函
数
27 {}
28 ~RBTreeNode()
29 {}
30 };
31
32 template<class T>
33 class RBTree //红黑树类定义
34 {
35 private:
36 RBTreeNode<T> *root; //根结点
37 public:
38 RBTree():root(NULL) //空树
39 {
40 }
41 bool Insert(const T& x) //插入函数
42 {
43 Insert(root,x);
44 }
45 protected:
46 bool Insert(RBTreeNode<T> *& t,const T& x)
47 {
48 RBTreeNode<T> *p = t;
49 RBTreeNode<T> *pr = NULL; //插入位置的父结点
50 while(p != NULL) //找到要插入的位置
51 {
52 if(x == p->data)
53 return false;
54
55 pr = p;
56
57 if(x < p->data)
58 p = p ->leftChild;
59 else
60 p = p->rightChild;
61 }
62
63 p = _BuyNode(x); //申请结点
64
65 if(pr == NULL) //插入的为根位置
66 {
67 t = p;
68 t->color = BLACK;
69 return true;
70 }
71
72 if(x < pr->data) //插入的位置为左子树
73 pr->leftChild = p;
74 else
75 pr->rightChild = p; //插入的位置为右子树
76 p->parent = pr;
77
78 _Balance_Tree(t,p); //调整树的位置 即平衡树
79 }
80 RBTreeNode<T>* _BuyNode(const T& x)
81 {
82 RBTreeNode<T> *p = new RBTreeNode<T>(x);
83 assert(p != NULL);
84 return p;
85 }
86 void _Balance_Tree(RBTreeNode<T> *& t,RBTreeNode<T> *p)
87 {
88 RBTreeNode<T> *s;
89 while(p->parent != NULL && p->parent->color == RED) //p插入的父结点的父亲的颜色是否为> 红色
90 {
91 if(p->parent == p->parent->parent->leftChild) //p的父亲是在外侧插入
92 {
93 s = p->parent->parent->rightChild; //s为插入结点的父结点的兄弟结点
94
95 if(s != NULL && s->color == RED) //只要看到有某结点X的两个子节点皆为红色,> 就把X改为红色,并把两个子节点改为黑色, 但是此时如果X的父结点p亦为红色,就得像状况1一样地做一次单旋转> 并改变颜色,或是像状况2一样地做一次双旋转并改变颜色。
96 {
97 p->parent->color = BLACK;
98 s->color = BLACK;
99 p->parent->parent->color = RED;
100 p = p->parent->parent;
101 continue;
102 }
103 else if(p == p->parent->rightChild) //情况2 <
104 {
105 p = p->parent;
106 RotateL(p);
107 }
108
109 p->parent->color = BLACK; //情况3
110 p->parent->parent->color = RED;
111 RotateR(p->parent->parent);
112 }
113 else
114 {
115 s = p->parent->parent->leftChild;
116
117 if(s != NULL && s->color == RED)
118 {
119 s->color = BLACK;
120 p->parent->color = BLACK;
121 p->parent->parent->color = RED;
122 p = p->parent->parent;
123 continue;
124 }
125 else if(p == p->parent->leftChild)
126 {
127 p = p->parent;
128 RotateR(p);
129 }
130
131 p->parent->color = BLACK;
132 p->parent->parent->color = RED;
133 RotateL(p->parent->parent);
134 }
135 }
136 t->color = BLACK;
137 }
138
139 /*
233 private:
234 void RotateR(RBTreeNode<T> * ptr) //右旋函数
235 {
236 RBTreeNode<T> *subR = ptr; //右结点
237 ptr = ptr->leftChild; //新的根结点
238 subR->leftChild = ptr->rightChild; //ptr成为新根前处理其右边的结点
239 if(ptr->rightChild != NULL) //如果ptr的右子女结点存在
240 ptr->rightChild->parent = subR;
241 if(subR->parent == NULL)
242 root = ptr;
243 else
244 {
245 if(subR == subR->parent->leftChild) //subR为父结点的的左子树
246 subR->parent->leftChild = ptr;
247 else
248 subR->parent->rightChild = ptr;
249 }
250 ptr->parent = subR->parent; //将父结点连接起来
251 ptr->rightChild = subR; //ptr成为新结点
252 subR->parent = ptr;
253 }
254 void RotateL(RBTreeNode<T> *ptr) //左旋函数
255 {
256 RBTreeNode<T> *subL = ptr; //左结点
257 ptr = ptr->rightChild; //新到的根节点
258 subL->rightChild = ptr->leftChild; //ptr成为新根前处理其左边的结点
259 if(ptr->leftChild != NULL) //如果ptr的左结点存在 连接其父结点
260 ptr->leftChild->parent = subL;
261 if(subL->parent == NULL) //如果到达了根结点
262 root = ptr;
263 else
264 {
265 if(subL == subL->parent->leftChild) //确定新根的位置
266 subL->parent->leftChild = ptr;
267 else
268 subL->parent->rightChild = ptr;
269 }
270 ptr->parent = subL->parent; //连接其父结点
271 ptr->leftChild = subL; //连接子女
272 subL->parent = ptr;
273 }
274 };
275
276
277
278 #endif
测试代码
1 #include"./rbtree.h"
2
3 int main()
4 {
5
6 RBTree<int> rb;
7 int ar[] = {100,70,80,50,40,75,73,72,74,71};
8 int n = sizeof(ar)/sizeof(int);
9
10 for(int i = 0; i < n; ++i)
11 {
12 rb.Insert(ar[i]);
13 }
14 return 0;
15 }
上面的做法太过于麻烦,每次都要判断结点是否为空,所以后面加入了头结点即哨兵位置。
github地址:这里
#ifndef _RBTREE_H
#define _RBTREE_H
#include<iostream>
#include<assert.h>
#include<stdlib.h>
#include<string.h>
using namespace std;
typedef enum{RED = 0,BLACK}COLOR;
typedef int Type;
typedef struct RBNode //结点声明
{
int value; //数据域
COLOR color; //颜色
struct RBNode* parent; //父结点
struct RBNode* left; //左右子结点
struct RBNode* right;
}RBNode;
typedef struct RBTree
{
RBNode *root; //根结点
RBNode *NIL; //哨兵位置
}RBTree;
RBNode* _Buynode(Type v) //申请结点函数
{
RBNode *s = (RBNode*)malloc(sizeof(RBNode)); //申请空间
assert(s != NULL);
memset(s,0,sizeof(RBNode)); //初始化
s->value = v;
s->color = RED;
return s;
}
void InitRBTree(RBTree &t) //初始化函数
{
t.NIL = _Buynode(0); //哨兵初始化
t.root = t.NIL;
t.NIL->color = BLACK;
}
void RotateL(RBTree &t,RBNode *p) //左旋
{
RBNode *s = p->right; //新的根结点
p->right = s->left; //s成为新根前扔掉其左边结点
if(s->left != NULL)
s->left->parent = p;
s->parent = p->parent; //连接父结点
if(p->parent == t.NIL) //p的父亲为空
t.root = s; //即根结点
else if(p == p->parent->left) //找到其应该存在的结点
p->parent->left = s;
else
p->parent->right = s;
s->left = p; //s成为新结点
p->parent = s;
}
void RotateR(RBTree &t,RBNode *p) //右旋
{
RBNode *s = p->left;
p->left = s->right;
if(s->right != NULL)
s->right->parent = p;
s->parent = p->parent;
if(p->parent != t.NIL)
t.root = s;
else if(p == p->parent->left)
p->parent->left = s;
else
p->parent->right = s;
s->right = p;
p->parent = s;
}
void Insert_Fixup(RBTree &t,RBNode *z) //删除调整函数
{
RBNode *y; //伯父结点
while(z->parent->color == RED) //其父结点为红色 就需要调整
{
if(z->parent == z->parent->parent->left) //z的父结点是在左子树
{
y = z->parent->parent->right; //伯父结点
if(y->color == RED) //伯父结点为红色
{
z->parent->color = BLACK;
y->color = BLACK;
z->parent->parent->color = RED;
z = z->parent->parent;
continue; //向上回朔
}
else if(z == z->parent->right) //伯父结点为黑色并且插入的新结点是在外侧
{
z = z->parent;
RotateL(t,z);
}
//插入节点是在内测的情况下
z->parent->parent->color = RED;
z->parent->color = BLACK;
RotateR(t,z->parent->parent);
}
else //z的父结点是在右子树
{
y = z->parent->parent->left;
if(y->color == RED)
{
z->parent->color = BLACK;
y->color = BLACK;
z->parent->parent->color = RED;
z = z->parent->parent;
continue;
}
else if(z == z->parent->left)
{
z = z->parent;
RotateR(t,z);
}
z->parent->parent->color = RED;
z->parent->color = BLACK;
RotateL(t,z->parent->parent);
}
}
t.root->color = BLACK;
}
bool Insert(RBTree &t,Type x) //插入函数
{
RBNode *pr = t.NIL;
RBNode *s = t.root;
while(s != t.NIL) //不是根结点 就寻找应该插入的位置
{
if(x == s->value)
return false;
pr = s;
if(x < s->value)
s = s->left;
else
s = s->right;
}
RBNode *q = _Buynode(x); //申请结点
q->parent = pr; //连接
q->left = t.NIL;
q->right = t.NIL;
q->color = RED;
if(pr == t.NIL)
t.root = q;
else if(x < pr->value)
pr->left = q;
else
pr->right = q;
Insert_Fixup(t,q);
return true;
}
RBNode* _Next(RBTree &t,RBNode *p) //找到p结点对应的右边的前驱
{
if(p != t.NIL && p->right != t.NIL)
{
p = p->right;
while(p->right != t.NIL)
p = p->left;
}
return p;
}
void Delete_Fixup(RBTree &t,RBNode *& x) //删除调整平衡函数
{
RBNode *w;
while(x != t.root && x->color == BLACK)
{
if(x == x->parent->left) //左分支
{
w = x->parent->right; //w是x的兄弟结点
if(w->color == RED)
{
w->color = BLACK;
x->parent->color = RED;
RotateL(t,x->parent);
}
if(w->left->color == BLACK && w->right->color == BLACK)
{
w->color = RED;
x = x->parent;
}
else if(w->right->color == BLACK)
{
w->left->color = BLACK;
w->color = RED;
RotateR(t,w);
w = x->parent->right;
}
// \ 情况
w->color = x->parent->color;
x->parent->color = BLACK;
w->right->color = BLACK;
RotateL(t,x->parent); //左转
x = t.root;
}
else //右分支
{
w = x->parent->left; //w是x的兄弟结点
if(w->color == RED)
{
w->color = BLACK;
x->parent->color = RED;
RotateR(t,x->parent);
}
if(w->left->color == BLACK && w->right->color == BLACK)
{
w->color = RED;
x = x->parent;
}
else if(w->left->color == BLACK)
{
w->right->color = BLACK;
w->color = RED;
RotateL(t,w);
w = x->parent->left;
}
w->color = x->parent->color;
x->parent->color = BLACK;
w->left->color = BLACK;
RotateR(t,x->parent);
x = t.root;
}
}
x->color = BLACK;
}
bool Remove(RBTree &t,Type x) //删除函数
{
RBNode *p = t.root;
RBNode *y;
RBNode *s;
while(p != t.NIL && p->value != x)
{
if(x < p->value)
p = p->left;
else
p = p->right;
}
if(p->left != t.NIL && p->right != t.NIL) //被删除的结点右两个子女结点
y = _Next(t,p); //找到内删除的结点的后继
else
y = p;
if(y->left != t.NIL) //如果即将删除的结点有左子女
s = y->left;
else //有右子女
s = y->right;
s->parent = y->parent; //连接父结点
if(y->parent == t.NIL) //要删除的结点是根结点
t.root = s;
else if(y == y->parent->left)
y->parent->left = s;
else
y->parent->right = s;
if(y != p)
p->parent->value = y->value; //用替换的结点的值去覆盖前面的结点
if(y->color == BLACK)
Delete_Fixup(t,s); //恢复平衡函数
delete y;
return true;
}
#endif
测试代码
#include"./rbtree.h"
int main()
{
int ar[] = {100,70,80,40,75,73,72,74};
int n = sizeof(ar) / sizeof(int);
RBTree rb;
InitRBTree(rb);
for(int i = 0; i < n; ++i)
{
Insert(rb,ar[i]);
}
Remove(rb,50);
return 0;
}