红黑树(R-B Tree)是一种特殊的二叉查找树。红黑树的每个节点上都有存储位表示节点的颜色,可以是红(Red)或黑(Black)。
红黑树的特性:
1)每个节点或者是黑色,或者是红色;
2)根节点是黑色;
3)每个叶子节点(NIL)是黑色。注意:这里叶子节点,是指为空(NULL)的叶子节点!
4)如果一个节点是红色的,则它的子节点必须是黑色;
5)从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点;
红黑树的应用:
红黑树的应用比较广泛,主要是用它来存储有序的数据,它的时间复杂度是,效率非常高,Java集合中的TreeSet和TreeMap,C++ STL中的set、map,以及Linux虚拟内存的管理,都是通过红黑树去实现的;
红黑树的左旋:
红黑树的右旋:
红黑树的插入:
step 1 : 将红黑树当作一颗二叉查找树,将节点插入;
step 2 :将插入的节点着色为"红色"
重新温习一下红黑树的特性:
1) 每个节点或者是黑色,或者是红色;
2) 根节点是黑色;
3) 每个叶子节点是黑色。 注意:这里叶子节点,是指为空的叶子节点!
4) 如果一个节点是红色的,则它的子节点必须是黑色的;
5) 从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点;
将插入的节点着色为红色,不会违背"特性(5)"!少违背一条特性,就意味着我们需要处理的情况越少。接下来,就要努力的让这棵树满足其它性质即可;满足了的话,它就又是一颗红黑树了。o(∩∩)o...哈哈
step 3 : 通过一系列的旋转或着色等操作,使之重新成为一颗红黑树。
第二步中,将插入节点着色为"红色"之后,不会违背"特性(5)"。那它到底会违背哪些特性呢?
1)对于"特性(1)",显然不会违背了。因为我们已经将它涂成红色了;
2)对于"特性(2)",显然也不会违背。在第一步中,我们是将红黑树当作二叉查找树,然后执行的插入操作。而根据二叉查找数的特点,插入操作不会改变根节点。所以,根节点仍然是黑色;
3)对于"特性(3)",显然不会违背了。这里的叶子节点是指的空叶子节点,插入非空节点并不会对它们造成影响。
4)对于"特性(4)",是有可能违背的!
那接下来,想办法使之"满足特性(4)",就可以将树重新构造成红黑树了;
红黑树的删除:
step 1 :将红黑树当作一颗二叉查找树,将节点删除。
这和"删除常规二叉查找树中删除节点的方法是一样的"。分3种情况:
1) 被删除节点没有儿子,即为叶节点。那么,直接将该节点删除就OK了;
2) 被删除节点只有一个儿子。那么,直接删除该节点,并用该节点的唯一子节点顶替它的位置;
3) 被删除节点有两个儿子。那么,先找出它的后继节点;然后把“它的后继节点的内容”复制给“该节点的内容”;之后,删除“它的后继节点”。在这里,后继节点相当于替身,在将后继节点的内容复制给"被删除节点"之后,再将后继节点删除。这样就巧妙的将问题转换为"删除后继节点"的情况了,下面就考虑后继节点。 在"被删除节点"有两个非空子节点的情况下,它的后继节点不可能是双子非空。既然"的后继节点"不可能双子都非空,就意味着"该节点的后继节点"要么没有儿子,要么只有一个儿子。若没有儿子,则按"情况 1 "进行处理;若只有一个儿子,则按"情况 2 "进行处理。
step 2 :通过"旋转和重新着色"等一系列来修正该树,使之重新成为一棵红黑树。
因为"第一步"中删除节点之后,可能会违背红黑树的特性。所以需要通过"旋转和重新着色"来修正该树,使之重新成为一棵红黑树;
实例:建立一棵红黑树,完成红黑树的遍历、查询最值、插入、删除、销毁等功能;
1、rbtree.h
//rbtree.h
#ifndef RBTREE_H_
#define RBTREE_H_
#include<iostream>
#include<iomanip>
using std::cout;
using std::endl;
using std::setw;
enum Color{RED, BLACK};
template<class T>
struct Node{
T key;
Color color;
Node<T> *parent;
Node<T> *left;
Node<T> *right;
//Node constructor
Node(T value, Color c, Node<T> *p, Node<T> *l, Node<T> *r)
:key(value), color(c), parent(p), left(l), right(r){
};
};
//get parent
template<class T>
Node<T>* getParent(Node<T> *node){
return node -> parent;
}
//set parent
template<class T>
void setParent(Node<T> *node, Node<T> *p){
node -> parent = p;
}
//get color
template<class T>
Color getColor(Node<T> *node){
return node -> color;
}
//set color
template<class T>
void setColor(Node<T> *node, Color c){
node -> color = c;
}
template<class T>
class RBTree{
private:
Node<T> *root;
public:
//RBTree constructor
RBTree():root(NULL){
};
//RBTree destructor
~RBTree(){
destroy(root);
};
//preOrder the RBTree
void preOrder(){
preOrder(root);
};
//inOrder the RBTree
void inOrder(){
inOrder(root);
};
//postOrder the RBTree
void postOrder(){
postOrder(root);
};
//get the maxmium value
T max(){
Node<T> *temp = max(root);
if(temp != NULL)
{
return temp -> key;
}
return (T)NULL;
};
//get the minimum value
T min(){
Node<T> *temp = min(root);
if(temp != NULL)
{
return temp -> key;
}
return (T)NULL;
};
//search the value
void search(T value){
search(root, value);
};
//iterative search the value
void iterativeSearch(T value){
iterativeSearch(root, value);
}
//get the presuccessor
Node<T>* presuccessor(Node<T> *node){
if(node -> left != NULL){
return max(node -> left);
}
Node<T> *temp = node -> parent;
while((temp != NULL) && (node == temp -> left) ){
node = temp;
temp = temp -> parent;
}
return temp;
};
//get the successor
Node<T>* successor(Node<T> *node){
if(node -> right != NULL){
return min(node -> right);
}
Node<T> *temp = node -> parent;
while( (temp != NULL)&&(node == temp -> right) ){
node = temp;
temp = temp -> parent;
}
return temp;
};
//insert the value
void insert(T value){
Node<T> *temp = NULL;
if((temp = new Node<T>(value, BLACK, NULL, NULL, NULL)) == NULL){
return;
}
insert(root, temp);
}
//remove the value
void remove(T value){
Node<T> *temp;
if((temp = search(root, value)) != NULL){
remove(root, temp);
}
}
//print the RBTree
void print(){
if(root != NULL){
print(root, root -> key, 0);
}
};
//destroy the RBTree
void destroy(){
destroy(root);
};
private:
//preOrder overload
void preOrder(Node<T> *node) const;
//inOrder overload
void inOrder(Node<T> *node) const;
//postOrder overload
void postOrder(Node<T> *node) const;
//search overload
Node<T>* search(Node<T> *node, T value) const;
//iterativeSearch overload
Node<T>* iterativeSearch(Node<T> *node, T value) const;
//max overload
Node<T>* max(Node<T> *node);
//min overload
Node<T>* min(Node<T> *node);
//left rotation
void leftRotate(Node<T>* &tree, Node<T> *node);
//right rotation
void rightRotate(Node<T>* &tree, Node<T> *node);
//insert overload
void insert(Node<T>* &tree, Node<T> *node);
//insert fix up
void insertFixUp(Node<T>* &tree, Node<T> *node);
//remove overload
void remove(Node<T>* &tree, Node<T> *node);
//remove fix up
void removeFixUp(Node<T>* &tree, Node<T> *node, Node<T> *p);
//destroy overload
void destroy(Node<T>* &tree);
//print overload
void print(Node<T> *node, T value, int direction);
};
template<class T>
void RBTree<T>::preOrder(Node<T> *node) const{
if(node != NULL){
cout << node -> key << " ";
preOrder(node -> left);
preOrder(node -> right);
}
}
template<class T>
void RBTree<T>::inOrder(Node<T> *node) const{
if(node != NULL){
inOrder(node -> left);
cout << node -> key << " ";
inOrder(node -> right);
}
}
template<class T>
void RBTree<T>::postOrder(Node<T> *node) const{
if(node != NULL){
postOrder(node -> left);
postOrder(node -> right);
cout << node -> key << " ";
}
}
template<class T>
Node<T>* RBTree<T>::search(Node<T> *node, T value) const{
if((node == NULL) || (value == node -> key)){
return node;
}
if(value < node -> key){
return search(node -> left, value);
}
if(value > node -> key){
return search(node -> right, value);
}
}
template<class T>
Node<T>* RBTree<T>::iterativeSearch(Node<T> *node, T value) const{
while((node != NULL) && (value != node -> key)){
if(value < node -> key){
node = node -> left;
}else{
node = node -> right;
}
}
return node;
}
template<class T>
Node<T>* RBTree<T>::max(Node<T> *node){
if(node == NULL){
return node;
}
while(node -> right != NULL){
node = node -> right;
}
return node;
}
template<class T>
Node<T>* RBTree<T>::min(Node<T> *node){
if(node == NULL){
return node;
}
while(node -> left != NULL){
node = node -> left;
}
return node;
}
template<class T>
void RBTree<T>::leftRotate(Node<T>* &tree, Node<T> *x){
//set y is x right child
Node<T> *y = x -> right;
//set y' left child as x'right child
x -> right = y -> left;
//judge whether y has left child
if(y -> left != NULL){
y -> left -> parent = x;
}
//set x's parent as y' parent
y -> parent = x -> parent;
//link y and x's parent
if(x -> parent == NULL){
root = y;
}else{
if(x == x -> parent -> left){
x -> parent -> left = y;
}else{
x -> parent -> right = y;
}
}
//set x as y's left child
y -> left = x;
//set y as x's parent
x -> parent = y;
}
template<class T>
void RBTree<T>::rightRotate(Node<T>* &tree, Node<T> *y){
//set x as y's left child
Node<T> *x = y -> left;
//set x 's right child as x's left child
y -> left = x -> right;
//judge whether x has right child
if(x -> right != NULL){
x -> right -> parent = x;
}
//link y's parent as x's parent
x -> parent = y -> parent;
if(y -> parent == NULL){
root = x;
}else{
if(y == y -> parent -> left){
y -> parent -> left = x;
}else{
y -> parent -> right = x;
}
}
//set y as x's right child
x -> right = y;
//set x as y's parent
y -> parent = x;
}
template<class T>
void RBTree<T>::insert(Node<T>* &tree, Node<T> *node){
Node<T> *temp1 = NULL;
Node<T> *temp2 = tree;
//step 1 : insert node as binary search tree
while(temp2 != NULL){
temp1 = temp2;
if(node -> key < temp2 -> key){
temp2 = temp2 -> left;
}else{
temp2 = temp2 -> right;
}
}
node -> parent = temp1;
if(temp1 != NULL){
if(node -> key < temp1 -> key){
temp1 -> left = node;
}else{
temp1 -> right = node;
}
}else{
root = node;
}
//step 2 : set node color as RED
node -> color = RED;
//step 3 : fix up the RBTree
insertFixUp(tree, node);
}
template<class T>
void RBTree<T>::insertFixUp(Node<T>* &tree, Node<T> *node){
Node<T> *p, *g;
while((p = getParent(node))&&(getColor(p) == RED)){
g = getParent(p);
if(p == g -> left){
//case 1 : uncle is RED
{
Node<T> *uncle = g -> right;
if((uncle != NULL) && (getColor(uncle) == RED)){
setColor(g, RED);
setColor(p, BLACK);
setColor(uncle, BLACK);
node = g;
continue;
}
}
//case 2 : uncle is right child(BLACK)
if(p -> right == node){
Node<T> *temp;
leftRotate(tree, p);
temp = p;
p = node;
node = temp;
}
//case 3 : uncle is left child(BLACK)
setColor(g, RED);
setColor(p, BLACK);
rightRotate(tree, g);
}
else{
//case 1 : uncle is RED
{
Node<T> *uncle = g -> left;
if(uncle && (getColor(uncle) == RED)){
setColor(g, RED);
setColor(p, BLACK);
setColor(uncle, BLACK);
node = g;
continue;
}
}
//case 2 : uncle is left child(BLACK)
if(p -> left == node){
Node<T> *temp;
rightRotate(tree, p);
temp = p;
p = node;
node = temp;
}
//case 3 : uncle is right child(BLACK)
setColor(g, RED);
setColor(p, BLACK);
leftRotate(tree, g);
}
}
//set root as black color
setColor(root, BLACK);
}
template<class T>
void RBTree<T>::remove(Node<T>* &tree, Node<T> *node){
Node<T> *chd, *pat;
Color clr;
//case 1 : the node has left and right child
if((node -> left != NULL) && (node -> right != NULL)){
//use successor to "replace" the node
Node<T> *rep = node;
rep = rep -> right;
while(rep -> left != NULL){
rep = rep -> left;
}
if(getParent(node) != NULL){
Node<T> *temp = getParent(node);
if(node == temp -> left){
temp -> left = rep;
}
else{
temp -> right = rep;
}
}else{
root = node;
}
chd = rep -> right;
pat = getParent(rep);
clr = getColor(rep);
if(pat == node){
pat = rep;
}else{
if(chd != NULL){
setParent(chd, pat);
}
rep -> right = node -> right;
setParent(node -> right, rep);
}
rep -> parent = node -> parent;
rep -> color = node -> color;
rep -> left = node -> left;
node -> left -> parent = rep;
if(clr == BLACK){
removeFixUp(tree, chd, pat);
}
delete node;
return;
}
//case 2 : node has only one child
if(node -> left != NULL){
chd = node -> left;
}else{
chd = node -> right;
}
pat = node -> parent;
clr = node -> color;
if(chd != NULL){
chd -> parent = pat;
}
if(pat != NULL){
if(node == pat -> left){
pat -> left = chd;
}else{
pat -> right = chd;
}
}else{
root = chd;
}
if(clr == BLACK){
removeFixUp(tree, chd, pat);
}
//case 3 : nod is leaf node
delete node;
}
template<class T>
void RBTree<T>::removeFixUp(Node<T>* &tree, Node<T> *node, Node<T> *p){
Node<T> *temp;
while(((!node || (getColor(node) == BLACK))) && (node != tree)){
if(p -> left == node){
temp = p -> right;
//case 1 : brother node is RED
if(getColor(temp) == RED){
setColor(p, RED);
setColor(temp, BLACK);
leftRotate(tree, p);
temp = p -> right;
}
//case 2 : brother node is BLACK
//case 2.1 both two children are BLACK
if(((!temp -> left) || (getColor(temp -> left) == BLACK)) && ((!temp -> right) ||(getColor(temp -> right) == BLACK)))
{
setColor(temp, RED);
node = p;
p = getParent(node);
}else{
//case 2.2 left child is RED, right child is BLACK
if((!temp -> right) || (getColor(node -> right) == BLACK)){
setColor(temp -> left, BLACK);
setColor(temp, RED);
rightRotate(tree, temp);
temp = p -> right;
}
//case 2.3 right child is RED
setColor(temp, getColor(p));
setColor(p, BLACK);
setColor(temp -> right, BLACK);
leftRotate(tree, p);
node = tree;
break;
}
}else{
temp = p -> left;
//case 1 : brother node is RED
if(getColor(temp) == RED){
setColor(p, RED);
setColor(temp, BLACK);
rightRotate(tree, p);
temp = p -> left;
}
//case 2 : brother node is BLACK
//case 2.1 both two children are BLACK
if(((!temp -> left) || (getColor(temp -> left) == BLACK)) && ((!temp -> right) ||(getColor(temp -> right) == BLACK)))
{
setColor(temp, RED);
node = p;
p = getParent(node);
}else{
//case 2.2 left child is RED, right child is BLACK
if((!temp -> left) || (getColor(node -> left) == BLACK)){
setColor(temp -> right, BLACK);
setColor(temp, RED);
leftRotate(tree, temp);
temp = p -> left;
}
//case 2.3 right child is RED
setColor(temp, getColor(p));
setColor(p, BLACK);
setColor(temp -> left, BLACK);
rightRotate(tree, p);
node = tree;
break;
}
}
}
if(node != NULL){
setColor(node, BLACK);
}
}
template<class T>
void RBTree<T>::destroy(Node<T>* &tree){
if(tree == NULL){
return;
}
if(tree -> left != NULL){
return destroy(tree -> left);
}
if(tree -> right != NULL){
return destroy(tree -> right);
}
delete tree;
tree = NULL;
}
template<class T>
void RBTree<T>::print(Node<T> *node, T value, int direction){
if(node != NULL){
if(direction == 0){
cout << setw(2) << node -> key << " (B) is root " << endl;
}else{
cout << setw(2) << node -> key << (getColor(node) == RED ? "(R)" : "(B)") << " is ";
cout << setw(2) << value << " 's " << setw(12) << (direction == 1 ? " right child " : " left child ") << endl;
}
print(node -> left, node -> key, -1);
print(node -> right, node -> key, 1);
}
}
#endif
2、main.cpp
//main.cpp
#include<iostream>
#include"rbtree.h"
using namespace std;
int main(){
RBTree<int> *rbtree = new RBTree<int>();
int arr[18] = {20, 30, 40, 10, 50, 60, 1, 5, 6, 4, 3, 2, 22, 44, 11, 66, 55, 33};
cout << " ********* insert ********** " << endl;
for(int i = 0; i < 18; i++){
rbtree -> insert(arr[i]);
}
cout << " ********* print ********** " << endl;
rbtree -> print();
cout << endl;
cout << " ********* preOrder ********** " << endl;
rbtree -> preOrder();
cout << endl;
cout << " ********* inOrder ********** " << endl;
rbtree -> inOrder();
cout << endl;
cout << " ********* postOrder ********** " << endl;
rbtree -> postOrder();
cout << endl;
cout << " the maxmium value in RBTree is " << rbtree -> max() << endl;
cout << " the minimum value in RBTree is " << rbtree -> min() << endl;
cout << " ********* remove (66) ********** " << endl;
rbtree -> remove(66);
rbtree -> print();
rbtree -> inOrder();
cout << endl;
cout << " ********* remove (11) ********** " << endl;
rbtree -> remove(11);
rbtree -> print();
rbtree -> inOrder();
cout << endl;
cout << " ********* destroy ********** " << endl;
rbtree -> destroy();
cout << " RBTree -- has been destroyed !" << endl;
cout << " done ." << endl;
return 0;
}
practice makes perfect !
参考博客:红黑树(一)之 原理和算法详细介绍