红黑树实现
红黑树
具体红黑树的基本概念见博客
上述博客中,由于是各处粘贴合成的,所以我只参考了开头一篇,仔细研读研读,插入和删除总结为一下两个图和代码:
具体代码
/*************************************************************************
> File Name: rdt.cpp
> Author: Duke-wei
> Mail: 13540639584@163.com
> Created Time: 2017年04月19日 星期三 20时21分57秒
************************************************************************/
#include<iostream>
#include<vector>
#include<queue>
#include<string>
#define DE_BUG 0
using namespace std;
//红黑树本质是一颗二叉查找树,又由于带红黑色,所以接近平衡。
//红黑树5个性质:
//1.每个结点要么是红的要么是黑的。
//2.根节点是黑的。
//3.每个叶子结点都是黑的。这里的叶子结点是指树尾结点的NULL结点。
//4.如果一个结点是红的,那么它的两个儿子都是黑的。
//5.对于任意结点而言,其到叶结点树尾端NIL指针的每条路劲都包含相同数目的黑结点。
//上述性质让红黑树的查找、插入、删除的时间复杂度最坏也是O(log n)。
//define struct rdt : red black tree
struct rdt{
bool isred;
int value;
rdt* ln;
rdt* rn;
rdt* pa;
rdt():isred(true),value(0),ln(NULL),rn(NULL),pa(NULL){}
rdt(int x):isred(true),value(x),ln(NULL),rn(NULL),pa(NULL){}
rdt(bool f,int x):isred(f),value(x),ln(NULL),rn(NULL),pa(NULL){}
};
rdt* search(rdt* root,int value);
bool rdt_add_adjust(rdt* root,rdt* p);
rdt* add_node(rdt* root,int value);
void rdt_del_adjust(rdt* root,rdt* p);
rdt* del_node(rdt* root,int value);
rdt* rdt_init(vector<int> &nums);
rdt* rdt_head(rdt* root);
void rdt_delete(rdt* root);
void rdt_bfs(vector<pair<int,int> >& data,rdt* root);
void rdt_print(rdt* root);
//=================================================下面是寻找插入节点的函数================
//在红黑树中搜索value值,如果找到则返回nullptr,否则返回带插入的位置的父节点指针。
rdt* search(rdt* root,int value){
rdt* p = root;
while(root!=NULL){
if(root->value>value){
p = root;
root = root->ln;
}else if(root->value<value){
p = root;
root = root->rn;
}else{
return NULL;
}
}
return p;
}
//=================================================下面是插入节点时的函数================
//调整红黑树,root为p的父节点,p为需要更新的结点。
bool rdt_add_adjust(rdt* root,rdt* p){
if(root==NULL){
p->isred = false;
return true;
}
if(!root->isred){
//黑父,直接插入,无需更新
return true;
}else{
//p_root是root的父节点,是p的祖父结点
rdt* p_root = root->pa;
//注意这里的祖父结点不会NULL,如果没有祖父结点则这个红黑树根节点是红的,所以违背原理。
if(root==p_root->ln){
//root 是p_root的左结点
if(p_root->rn!=NULL&&p_root->rn->isred){
//叔父结点是红的
root->isred = false;
p_root->rn->isred = false;
p_root->isred = true;
rdt_add_adjust(p_root->pa,p_root);
}else{
//叔父结点是黑的
if(p==root->ln){
//p是root的左结点,LL旋转
//先记录root的右结点和p_root的父节点。
rdt* rrn = root->rn; //记录兄弟结点。可能为NULL
rdt* pp_root = p_root->pa; //记录祖父结点的父节点。可能为NULL
root->rn = p_root;
root->pa = p_root->pa;
p_root->ln = rrn;
p_root->pa = root;
if(rrn!=NULL) rrn->pa = p_root;
root->isred = false;
p_root->isred = true;
if(pp_root==NULL){
return true;
}else{
if(p_root==pp_root->ln){
pp_root->ln = root;
}else{
pp_root->rn = root;
}
}
}else{
//p是root的右结点,LR旋转 并且父节点是祖父结点的左结点。
rdt* pp_root = p_root->pa; //记录祖父结点的父节点,可能为NULL
if(p->ln!=NULL){
root->rn = p->ln;
root->rn->pa = root;
}else{
root->rn = NULL;
}
root->pa = p;
if(p->rn!=NULL){
p_root->ln = p->rn;
p_root->ln->pa = p_root;
}else{
p_root->ln = NULL;
}
p_root->pa = p;
p->ln = root;
p->rn = p_root;
p->pa = pp_root;
p->isred = false;
p_root->isred = true;
if(pp_root==NULL){
return true;
}
if(p_root==pp_root->ln){
pp_root->ln = p;
}else{
pp_root->rn = p;
}
}
}
}else{
//root 是p_root的右结点
if(p_root->ln!=NULL&&p_root->ln->isred){
//叔父结点是红的
root->isred = false;
p_root->ln->isred = false;
p_root->isred = true;
rdt_add_adjust(p_root->pa,p_root);
}else{
//叔父结点是黑的
if(p==root->ln){
//p是root的左结点,RL旋转
rdt* pp_root = p_root->pa;
if(p->ln!=NULL){
p_root->rn = p->ln;
p_root->rn->pa = p_root;
}else{
p_root->rn = NULL;
}
p_root->pa = p;
if(p->rn!=NULL){
root->ln = p->rn;
root->ln->pa = root;
}else{
root->ln = NULL;
}
root->pa = p;
p->ln = p_root;
p->rn = root;
p->pa = pp_root;
p->isred = false;
p_root->isred = true;
if(pp_root==NULL){
return true;
}
if(p_root==pp_root->ln){
pp_root->ln = p;
}else{
pp_root->rn = p;
}
}else{
//p是root的右结点,RR旋转
//rln root left node
rdt* rln = root->ln; //记录p的兄弟结点,可能为NULL
//pp_root is parent of p_root which is parent of root;
rdt* pp_root = p_root->pa; //记录祖父结点的父结点,可能为NULL
root->ln = p_root;
root->pa = pp_root;
p_root->rn = rln;
p_root->pa = root;
if(rln!=NULL) rln->pa = p_root;
root->isred = false;
p_root->isred = true;
if(pp_root==NULL){
return true;
}else{
if(p_root==pp_root->ln){
pp_root->ln = root;
}else{
pp_root->rn = root;
}
}
}
}
}
}
return true;
}
//插入一个值到红黑树并调整树
rdt* add_node(rdt* root,int value){
//先加入该结点(新插入结点默认都是红的)
rdt* new_node = new rdt(value);
if(root==NULL){
new_node->isred = false;
return new_node;
}
rdt* p = search(root,value);
if(p==NULL){
delete new_node;
return NULL;
}
if(p->value > value)
p->ln = new_node;
else
p->rn = new_node;
new_node->pa = p;
rdt_add_adjust(p,new_node);
rdt* head = rdt_head(p);
return head;
}
//==========================================以下是删除节点的函数======================
//这个函数处理删除节点后的树的调节
//参数是带调节的点P和P的父节点root
//该函数需要调节的有一下情况:
//--1.p的兄弟结点是红的:
//-----通过变换,继续迭代修正。
//--2.p的兄弟结点是黑的:
//-----2.1.黑兄弟有两个黑色侄子
//--------2.1.1.红色的父亲
//--------2.1.2.黑色的父亲
//-----2.2.黑兄弟有左红侄子
//-----2.3.黑兄弟有右红侄子
void rdt_del_adjust(rdt* root,rdt* p){
if(p==root->ln){
//注意p的兄弟结点一定不会是空的,通过红黑树的性质和删除节点前的情况可知。
rdt* pu = root->rn;
if(pu->isred){
//p的兄弟结点是红的,通过红黑树的性质可知,p的父节点一定是黑的。p的兄弟结点的子节点一定也是黑的或是空
//此时,只需要RR旋转,构造成红父黑兄的情况。
//处理后降低了一层,继续迭代。
rdt* pul = pu->ln;
root->rn = pul;
//这里的pul其实可以推导出,它一定不会为空的。
if(pul!=NULL) pul->pa = root;
pu->ln = root;
pu->pa = root->pa;
root->pa = pu;
//这里注意root是根结点的情况
if(pu->pa!=NULL){
if(pu->pa->ln==root){
pu->pa->ln = pu;
}else{
pu->pa->rn = pu;
}
}
pu->isred = false;
root->isred = true;
rdt_del_adjust(root,p);
}else{
//p的兄弟结点是黑的
if(pu->rn!=NULL&&pu->rn->isred){
//结点p有右红侄子
//实行RR旋转
rdt* pul = pu->ln;
root->rn = pul;
if(pul!=NULL) pul->pa = root;
pu->ln = root;
pu->pa = root->pa;
root->pa = pu;
//这里注意root是根结点的情况
if(pu->pa!=NULL){
if(root==pu->pa->ln){
pu->pa->ln = pu;
}else{
pu->pa->rn = pu;
}
}
pu->isred = root->isred;
root->isred = false;
pu->rn->isred = false;
}else if(pu->ln!=NULL&&pu->ln->isred){
//结点p有左红侄子
//进行RL旋转
//pul是p兄弟的左节点
rdt* pul = pu->ln;
//pul是p兄弟的左节点的左节点
rdt* pull = pul->ln;
//pul是p兄弟的左节点的右节点
rdt* pulr = pul->rn;
root->rn = pull;
if(pull!=NULL) pull->pa = root;
pu->ln = pulr;
if(pulr!=NULL) pulr->pa = pu;
pul->pa = root->pa;
root->pa = pul;
pul->ln = root;
pul->rn = pu;
pu->pa = pul;
//这里注意root是根结点的情况
if(pul->pa!=NULL){
if(root==pul->pa->ln){
pul->pa->ln = pul;
}else{
pul->pa->rn = pul;
}
}
pul->isred = root->isred;
root->isred = false;
}else{
//结点p有两个黑的侄子
if(root->isred){
//红父
root->isred = false;
pu->isred = true;
if(p!=NULL) p->isred = false;
}else{
//黑父
if(p!=NULL){
root->isred = p->isred;
}else{
root->isred = false;
}
pu->isred = true;
if(p!=NULL) p->isred = false;
}
}
}
}else{
rdt* pu = root->ln;
if(pu->isred){
//p的兄弟结点是红的
//进行LL旋转
//处理后降低了一层,继续迭代。
rdt* pur = pu->rn;
root->ln = pur;
//其实这里的pur不会为空
if(pur!=NULL) pur->pa = root;
pu->rn = root;
pu->pa = root->pa;
root->pa = pu;
//这里注意root是根结点的情况
if(pu->pa!=NULL){
if(pu->pa->ln==root){
pu->pa->ln = pu;
}else{
pu->pa->rn = pu;
}
}
pu->isred = false;
root->isred = true;
rdt_del_adjust(root,p);
}else{
//p的兄弟结点是黑的
if(pu->ln!=NULL&&pu->ln->isred){
//结点p有左红侄子
//实行LL旋转
rdt* pur = pu->rn;
root->ln = pur;
if(pur!=NULL) pur->pa = root;
pu->rn = root;
pu->pa = root->pa;
root->pa = pu;
//这里注意root是根结点的情况
if(pu->pa!=NULL){
if(root==pu->pa->ln){
pu->pa->ln = pu;
}else{
pu->pa->rn = pu;
}
}
pu->isred = root->isred;
root->isred = false;
pu->ln->isred = false;
}else if(pu->rn!=NULL&&pu->rn->isred){
//结点p有右红侄子
//进行LR旋转
//pur是p兄弟的右节点
rdt* pur = pu->rn;
//purl是p兄弟的右节点的左节点
rdt* purl = pur->ln;
//purr是p兄弟的右节点的右节点
rdt* purr = pur->rn;
root->rn = purr;
if(purr!=NULL) purr->pa = root;
pu->ln = purl;
if(purl!=NULL) purl->pa = pu;
pur->pa = root->pa;
root->pa = pur;
pur->ln = pu;
pur->rn = root;
pu->pa = pur;
//这里注意root是根结点的情况
if(pur->pa!=NULL){
if(root==pur->pa->ln){
pur->pa->ln = pur;
}else{
pur->pa->rn = pur;
}
}
pur->isred = root->isred;
root->isred = false;
}else{
//结点p有两个黑的侄子
if(root->isred){
//红父
root->isred = false;
pu->isred = true;
if(p!=NULL) p->isred = false;
}else{
//黑父
if(p!=NULL){
root->isred = p->isred;
}else{
root->isred = false;
}
pu->isred = true;
if(p!=NULL) p->isred = false;
}
}
}
}
}
rdt* del_node(rdt* root,int value){
//首先找到需要删除的点。
while(root!=NULL){
if(root->value > value) root = root->ln;
else if(root->value < value) root = root->rn;
else break;
}
//没找到,返回false
if(root==NULL) return NULL;
if(root->ln==NULL&&root->rn==NULL){
if(root->isred){
//找到需要删除的结点,如果是红色的叶子节点,直接删除。
rdt* rp = root->pa;
if(rp->ln==root){
rp->ln = NULL;
}else{
rp->rn = NULL;
}
rdt_delete(root);
return rp;
}
//找到需要删除的结点,如果是黑色叶子结点,看它的父节点,如果是空,则该节点是根结点。
//这里特殊处理一下,删根节点直接将它置为红色结点,放回空。
if(root->pa==NULL){
root->isred = true;
return NULL;
}
}
//如果是黑的单支结点或者是黑的叶子结点,如下处理。
//存在情况:
//1.纯黑色叶子结点,这个情况合并在3中。
//2.黑色单支结点,左右中有一个红色叶子结点。
//3.黑色单支结点,左或右是一个黑色结点(包括哨兵结点)
if(root->ln==NULL||root->rn==NULL){
if(root->ln!=NULL&&root->ln->isred){
//左节点非空,而且是红色的,直接将值赋给root。
root->value = root->ln->value;
rdt_delete(root->ln);
root->ln = NULL;
}else if(root->ln!=NULL&&!root->ln->isred){
//否则为黑色单支结点,子节点是黑色的。
root->value = root->ln->value;
rdt_delete(root->ln);
root->ln = NULL;
rdt_del_adjust(root->pa,root);
}else if(root->rn!=NULL&&root->rn->isred){
//右节点非空且为红色。直接将值赋给root。
root->value = root->rn->value;
rdt_delete(root->rn);
root->rn = NULL;
}else if(root->rn!=NULL&&!root->rn->isred){
//否则为黑色单支结点,子节点是黑色的。
root->value = root->rn->value;
rdt_delete(root->rn);
root->rn = NULL;
rdt_del_adjust(root->pa,root);
}else{
//纯黑色叶子结点处理
rdt* pr = root->pa;
if(root==pr->ln){
pr->ln = NULL;
}else{
pr->rn = NULL;
}
rdt_delete(root);
root = NULL;
rdt_del_adjust(pr,root);
return pr;
}
}else{
//如果都不是,则找root左子树的最大值结点A,替换root,然后递归删除该结点A。
rdt* p = root->ln;
while(p->rn!=NULL){
p = p->rn;
}
root->value = p->value;
return del_node(p,p->value);
}
return root;
}
//==========================================以下是删除节点的内存的函数==================
//删除结点
void rdt_delete(rdt* root){
if(root==NULL) return ;
rdt_delete(root->ln);
rdt_delete(root->rn);
delete root;
root = NULL;
}
//==========================================以下是返回头结点的函数======================
rdt* rdt_head(rdt* p){
if(p==NULL) return NULL;
while(p->pa!=NULL){
p= p->pa;
}
return p;
}
//==========================================以下是通过数组构建红黑树的函数==============
//给定一个vector<int> 构建一个红黑树,放回开始结点。
rdt* rdt_init(vector<int> &nums){
if(nums.empty()) return NULL;
rdt* root = new rdt(false,nums[0]);
rdt* old_root=root;
if(nums.size()==1){
return root;
}else{
for(int i=1;i<(int)nums.size();++i){
root = add_node(old_root,nums[i]);
if(DE_BUG) cout<<"value: "<<nums[i]<<" root: "<<(root==NULL?-1:old_root->value)<<endl;
if(root==NULL) continue;
if(DE_BUG) rdt_print(root);
if(DE_BUG) cout<<endl;
old_root = root;
}
}
rdt* head = rdt_head(old_root);
return head;
}
//==========================================以下是打印红黑树的函数======================
//广度遍历整个树,将数据存在data中。
void rdt_bfs(vector<pair<int,int> >& data,rdt* root){
queue<rdt*> rdt_q;
rdt_q.push(root);
rdt* p;
data.push_back(pair<int,int>(root->value,root->isred));
while(!rdt_q.empty()){
p = rdt_q.front();
rdt_q.pop();
if(p->ln!=NULL){
rdt_q.push(p->ln);
data.push_back(pair<int,int>(p->ln->value,p->ln->isred));
}else{
data.push_back(pair<int,int>(-1,-1));
}
if(p->rn!=NULL){
rdt_q.push(p->rn);
data.push_back(pair<int,int>(p->rn->value,p->rn->isred));
}else{
data.push_back(pair<int,int>(-1,-1));
}
}
}
//打印红黑树,通过广度遍历后打印数据。
void rdt_print(rdt* root){
vector<pair<int,int> > data;
rdt_bfs(data,root);
if(DE_BUG) cout<<"bfs rdt ,data is "<<data.size()<<endl;
int layer=1,tt = 1,t=0,sum=1;
while(sum<=(int)data.size()-1){
tt<<=1;
sum += tt;
layer++;
}
int count = 1;
while(layer>=0){
for(int i=0;i<layer;++i) cout<<" ";
for(int i=0;i<count;++i){
cout<<to_string(data[t].first)<<","<<to_string(data[t].second)<<" ";
t++;
if(t>=(int)data.size()) return ;
}
cout<<endl;
layer--;
count <<= 1;
}
}
//====================================main函数=================================
int main(){
//rdt root(false,2);
//rdt t1(false,1);
//rdt t2(false,3);
//root.ln = &t1;
//root.rn = &t2;
//t1.pa = &root;
//t2.pa = &root;
//rdt_print(&root);
//return 0;
int nm[10] = {1,3,5,6,8,9,10,4,7,2};
vector<int> nums(nm,nm+10);
rdt* root = rdt_init(nums);
rdt_print(root);
int va;
rdt* p;
cout<<"\ninput value for del: ";
while(cin>>va){
if(va==-1) break;
p = del_node(root,va);
if(p!=NULL){
rdt* head = rdt_head(p);
root = head;
cout<<endl;
rdt_print(head);
}else{
if(root->isred){
cout<<"the rdt is empty"<<endl;
break;
}else{
cout<<"\nerror ,no such value"<<endl;
}
}
cout<<"\ninput value for del: ";
}
rdt* h = rdt_head(root);
if(h!=NULL) rdt_delete(h);
return 0;
}