在寫完線性容器以後,再來看關聯性容器。在關聯性容器中,set,map容器都是基於紅黑樹而實現的,故花了幾天時間寫下來紅黑樹的代碼。其原理可以參考算法導論。在寫過程中也參照了網上別人寫的代碼。其代碼實現如下:
#include<iostream>
using namespace std;
//紅黑樹
class RB_Tree
{
private:
enum COLOR{RED,BLACK};
class RB_Node
{
public:
RB_Node *left;
RB_Node *right;
RB_Node *parent;
COLOR RB_COLOR;
int data;
RB_Node(COLOR _COLOR=BLACK,int _data=0):left(NULL),right(NULL),parent(NULL),data(_data),RB_COLOR(_COLOR){}
};
private:
RB_Node *root; //紅黑樹的根節點
RB_Node *nullNode; //空節點,黑色的
//插入完成後要記得修復,使其滿足紅黑樹的性質
//插入時中的三種情況
void InsertFixUp(RB_Node *node)
{
while(node->parent->RB_COLOR==RED)
{
//插入節點爲父節點的左孩子
if(node->parent->left==node)
{
RB_Node *uncle=node->parent->parent->right;
if(uncle->RB_COLOR==RED) //case 1
{
node->parent->RB_COLOR=BLACK;
uncle->RB_COLOR=BLACK;
node=node->parent->parent;
node->RB_COLOR=RED;
}
else
{
if(node->parent==node->parent->parent->right) //case 2
{
node=node->parent;
right_rotate(node);
// goto double_left_rotate;
}
//case2結束以後直接進入case3,或者直接進入case3
// double_right_rotate:
else{
node->parent->RB_COLOR=BLACK;
node->parent->parent->RB_COLOR=RED;
right_rotate(node->parent->parent);
}
}
}
//當節點爲爲父節點的右孩子
else
{
RB_Node *uncle=node->parent->parent->left;
if(uncle->RB_COLOR==RED) //case 1
{
node->parent->RB_COLOR=BLACK;
uncle->RB_COLOR=BLACK;
node=node->parent->parent;
node->RB_COLOR=RED;
}
else
{
if(node->parent==node->parent->parent->left) //case 2
{
node=node->parent;
left_rotate(node);
// goto double_right_rotate;
}
//case2結束以後直接進入case3,或者直接進入case3
// double_left_rotate:
else{
node->parent->RB_COLOR=BLACK;
node->parent->parent->RB_COLOR=RED;
left_rotate(node->parent->parent);
}
}
}
}
if(node==root)
node->RB_COLOR=BLACK;
}
//左旋轉
void left_rotate(RB_Node *node)
{
RB_Node *temp=node->right;
temp->parent=node->parent;
if(node->parent==nullNode)
root=temp;
else
{
if(node==node->parent->left)
node->parent->left=temp;
else
node->parent->right=temp;
}
node->right=temp->left;
if(temp->left!=nullNode)
temp->left->parent=node;
node->parent=temp;
temp->left=node;
}
//右旋轉
void right_rotate(RB_Node *node)
{
RB_Node *temp=node->left;
temp->parent=node->parent;
if(node==root) //等價於node->parent==NULL
root=temp;
else
{
if(node==node->parent->left)
node->parent->left=temp;
else
node->parent->right=temp;
}
node->left=temp->right;
if(temp->right!=nullNode)
temp->right->parent=node;
node->parent=temp;
temp->right=node;
}
//找到值爲value的節點
RB_Node* find_node(int value)
{
RB_Node *temp=root;
while(temp!=nullNode)
{
if(temp->data>value)
temp=temp->left;
else if(temp->data<value)
temp=temp->right;
else
break;
}
return temp;
}
//該函數的功能是用來在刪除節點時,如果節點存在左右孩子節點則找到應該替換的節點
RB_Node* find_delete_node(RB_Node *node)
{
if(node->left==nullNode||node==nullNode)
return nullNode;
RB_Node *temp=node->left;
while(temp->right!=nullNode)
temp=temp->right;
return temp;
}
void deleteFixUp(RB_Node *node)
{
RB_Node *temp=node;
while(temp->RB_COLOR==BLACK&&temp!=root)
{
RB_Node *brother;
//該節點爲父節點的左節點
if(temp==temp->parent->left)
{
brother=temp->parent->right;
if(brother->RB_COLOR==RED) //case 1
{
temp->parent->RB_COLOR=RED;
brother->RB_COLOR=BLACK;
//在旋轉之後兄弟節點會發生變化,因此在旋轉之前就將兄弟節點給換過來
brother=brother->left;
left_rotate(temp->parent);
}
//case 1結束後,會進入case2/case3/case4
if(brother->left->RB_COLOR==BLACK&&brother->right->RB_COLOR==BLACK) //case2
{
brother->RB_COLOR=RED;
temp=temp->parent;
}
else
{
if(brother->right->RB_COLOR==BLACK) //case 3
{
brother->RB_COLOR=RED;
brother->left->RB_COLOR=BLACK;
brother=brother->left;
right_rotate(brother->parent);
}
//進入case4情況
brother->RB_COLOR=temp->parent->RB_COLOR;
brother->right->RB_COLOR=temp->parent->RB_COLOR=BLACK;
left_rotate(temp->parent);
temp=root;
}
}
else //該節點爲父節點的右孩子
{
brother=temp->parent->left;
if(brother->RB_COLOR==RED) //case 1
{
temp->parent->RB_COLOR=RED;
brother->RB_COLOR=BLACK;
//在旋轉之後兄弟節點會發生變化,因此在旋轉之前就將兄弟節點給換過來
brother=brother->right;
right_rotate(temp->parent);
}
//case 1結束後,會進入case2/case3/case4
if(brother->left->RB_COLOR==BLACK&&brother->right->RB_COLOR==BLACK) //case2
{
brother->RB_COLOR=RED;
temp=temp->parent;
}
else
{
if(brother->right->RB_COLOR==BLACK) //case 3
{
brother->RB_COLOR=RED;
brother->left->RB_COLOR=BLACK;
brother=brother->left;
left_rotate(brother->parent);
}
//進入case4情況
brother->RB_COLOR=temp->parent->RB_COLOR;
brother->right->RB_COLOR=temp->parent->RB_COLOR=BLACK;
right_rotate(temp->parent);
temp=root;
}
}
}
//最後退出來的時候記得將節點顏色變成黑色
temp->RB_COLOR=BLACK;
}
public:
//構造函數初始化
RB_Tree()
{
nullNode=new RB_Node();
root=nullNode;
nullNode->left=nullNode->right=nullNode->parent=nullNode;
}
//紅黑樹的插入操作
void insert_node(int value)
{
RB_Node *node=new RB_Node(RED,value);
node->left=node->right=node->parent=nullNode;
if(root==nullNode) //先把空樹的情況處理掉
{
root=node;
root->RB_COLOR=BLACK;
return ;
}
RB_Node *temp=root;
RB_Node *insert_parent;
while(temp!=nullNode)
{
insert_parent=temp;
if(temp->data>value)
temp=temp->left;
else
temp=temp->right;
}
if(insert_parent->data>value)
insert_parent->left=node;
else
insert_parent->right=node;
node->parent=insert_parent;
//完成插入後的修復工作
InsertFixUp(node);
}
//紅黑樹的刪除操作
void delete_node(int value)
{
RB_Node *node=find_node(value);
RB_Node *delete_node,*delete_node_child;
if(node->left==nullNode||node->right==nullNode)
delete_node=node;
else
delete_node=find_delete_node(node);
//如果刪除點不是node,則應該將delete_node值複製過來
if(delete_node!=node)
node->data=delete_node->data;
if(delete_node->left!=nullNode)
delete_node_child=delete_node->left;
else if(delete_node->right!=nullNode)
delete_node_child=delete_node->right;
else
delete_node_child=nullNode;
delete_node_child->parent=delete_node->parent;
if(delete_node==root)
root=delete_node_child;
else
{
if(delete_node==delete_node->parent->left)
delete_node->parent->left=delete_node_child;
else
delete_node->parent->right=delete_node_child;
}
if(delete_node->RB_COLOR==BLACK)
deleteFixUp(delete_node_child);
delete delete_node;
}
//打印節點
void display()
{
display(root);
}
void display(RB_Node *node)
{
if(node->left!=nullNode)
display(node->left);
if(node!=nullNode)
cout<<node->data<<" 顏色爲:"<<node->RB_COLOR<<endl;
if(node->right!=nullNode)
display(node->right);
}
};
int main()
{
RB_Tree q;
int i;
for(i=1;i<10;i++)
q.insert_node(i);
q.display();
for(i=1;i<10;i++)
{
q.delete_node(i);
cout<<"刪除"<<i<<"後:"<<endl;
q.display();
}
return 0;
}
其運行結果圖如下: