索引红黑树的插入和删除实现
思路:
(1)插入:
根节点设置为黑色
插入节点初始为红色,先确定插入位置,当父节点为红色时需要调整。
由于需要保证root指向树的唯一入口,并且调整中的旋转会对root产生影响,所以调整时,需要分为:
1.插入节点的祖父节点是根节点
2.插入节点的祖父节点不是根节点
区别:是否需要回溯(将插入节点的祖父节点看做插入节点进行调整)
旋转调整:
(1)兄弟节点是黑色或者为空时:需要旋转(参考AVL的LL型、RR型、LR型、RL型)
(2)兄弟节点是红色时:变色不旋转
(2)查询:
根据关键字查询:直接比对数据即可
根据索引查询:利用leftsize计算节点在有序序列中的位置索引
(3)删除:
根据关键字删除,根据索引删除
先根据删除条件找到要删除的节点,删除之后进行调整。
如果删除节点是红色节点,则该节点要么是叶节点,要么度为2。
(原因:根据红黑树的性质:不会出现度为1的情况,因为如果度为1,不能出现连续红,
则唯一子节点一定是黑色,因为黑色路径长度相同的性质,所以不可能出现度为1的情况)
如果是叶节点,直接删除(设置为null即可)
否则寻找前驱节点(左子树中最右边的节点)进行替换
如果前驱节点是红色,直接删除
否则需要回溯
如果删除的是黑色节点,根据度进行调整:
1.度为2:找前驱节点进行替换,思路同上
2.度为1:则只可能有一个红色的子节点,直接替换删除即可
3.度为0,分情况:
(1)兄弟节点为红色:
将父节点变红,兄弟节点变黑,旋转,继续回溯
(2)兄弟节点是黑色,远房侄子为红色:
将父节点和兄弟节点交换颜色,将远房侄子变成黑色,删除节点,旋转调整,不用回溯。
(3)兄弟节点是黑色,近邻侄子为红色:
将兄弟节点和近邻侄子节点交换颜色,旋转,调整,删除即可,不用回溯
(4)父节点为红色,兄弟节点为黑色,且兄弟节点是叶节点:
将父节点和兄弟节点交换颜色,直接删除,不用回溯
(5)除以上情况的情况:将兄弟节点变成红色,并回溯到父节点
总结:删除时看颜色的顺序:先看自己(真实删的节点),再看孩子,再看兄弟,再看侄子,最后看父亲
代码实现:
1.节点类和索引红黑树类的声明:
#include<iostream>
#include<time.h>
#include<queue>
using namespace std;
template<class k,class t>
class note
{
public:
pair<k, t>data;
char color = 'r';
int leftsize = 0;//用来标识该节点的左子树的节点数,也是该节点在以其为根节点的子树的索引
note<k, t>* leftchild = NULL;
note<k, t>* rightchild = NULL;
note<k, t>* parent = NULL;//增加一个父节点,替换搜索父节点的开销
note<k, t>() = default;
note<k, t>(pair<k, t>d);
};
template<class k,class t>
note<k, t>::note(pair<k, t>d) {
data = d;
}
template<class k,class t>
class indexedRedBlackTree
{/*也是搜索树的性质(和第一题一样),只是每一个节点还有一个leftsize域*/
public:
note<k, t>* root = NULL;
//函数根据测试顺序排序:
void insert(pair<k, t>p);//插入数对p
void RR(bool isroot, note<k, t>* n, note<k, t>* temp, note<k, t>* tempfu, note<k, t>* tempfufu);
void LL(bool isroot, note<k, t>* n, note<k, t>* temp, note<k, t>* tempfu,note<k, t>* tempfufu);//只负责旋转,不负责着色
void insertadjust(bool isroot, note<k, t>* n, note<k, t>* temp, note<k, t>* tempfu, note<k, t>* tempfufu);
void ascend(note<k, t>* p);//按关键字升序输出所有数对
t find(k key);//返回关键字对应的数据
pair<k, t>get(int index);//返回第index个数对
void deleteindex(int index,pair<k,t>&x);//根据给定的索引,删除其数对
void deletekey(k key, t& x);//删除关键字为key的数对
void deletecommon(note<k,t>*temp,note<k,t>*tempfu);
note<k, t>* case5(note<k, t>* d);
};
2.插入和旋转实现:
template<class k,class t>
void indexedRedBlackTree<k, t>::insert(pair<k, t>p) //参数:要插入节点的data
{
if (root == NULL) //根节点颜色为黑色:
{
note<k, t>* n = new note<k, t>(p);/*n->data = p;*/
root = n;
root->color = 'b';
}
else//注:搜索树都是插入到叶节点处,所以刚开始的leftsize都是0,旋转之后再进行调整
{
//寻找要进行插入的位置,以及父节点,祖父节点,祖先节点:
queue<note<k, t>*>q; //保存插入节点在其的左子树中的路径节点,维护leftsize
note<k, t>* temp = root; //插入节点的父节点
note<k, t>* tempfu = root;//temp的父节点
note<k, t>* tempfufu = root;//temp的祖父节点
while (true)
{
if (p.first == temp->data.first)
{
cout << p.first<<"节点已存在" << endl;
return;
}
if (p.first < temp->data.first)
{
q.push(temp);
if (temp->leftchild == NULL)
{
note<k, t>* n = new note<k, t>(p);
temp->leftchild = n;
n->parent = temp;
if (temp->color == 'r') //当出现连续红时,才需要调整
{
if (tempfu->data.first == root->data.first) //父节点是根节点
{
insertadjust(true, n, temp, tempfu, tempfufu);
}
else
{
insertadjust(false, n, temp, tempfu, tempfufu);
}
}
break;
}
else
{
tempfufu = tempfu;
tempfu = temp;
temp = temp->leftchild;
}
}
else
{
if (temp->rightchild==NULL)
{
note<k, t>* n = new note<k, t>(p);
temp->rightchild = n;
n->parent = temp;
if (temp->color == 'r')
{
if (tempfu->data.first == root->data.first)
{
insertadjust(true, n, temp, tempfu, tempfufu);
}
else
{
insertadjust(false, n, temp, tempfu, tempfufu);
}
}
break;
}
else
{
tempfufu = tempfu;
tempfu = temp;
temp = temp->rightchild;
}
}
}
//更新队列中保存节点的leftsize值:
while (!q.empty())
{
temp= q.front();
q.pop();
temp->leftsize++;
}
}
}
template<class k, class t>
void indexedRedBlackTree<k, t>::insertadjust(bool isroot, note<k, t>* n, note<k, t>* temp, note<k, t>* tempfu, note<k, t>* tempfufu)
{ /*
函数作用:调整出现的连续红
参数:tempfu是否是根节点,插入节点,插入节点的父节点A,A的父节点,A的祖父节点(要考虑四代)
*/
if (isroot)//表示tempfu是根节点,即插入节点的祖父节点是根节点
{
//左子树:
if (temp->data.first < root->data.first)
{
//兄弟节点是黑色或者为空时:旋转,调色
if (root->rightchild == NULL || root->rightchild->color == 'b')
{
//LL型:对tempfu进行LL旋转
if (n->data.first < temp->data.first)
{
LL(true, n, temp, tempfu,tempfufu);//旋转后需要自己进行调色
root->rightchild->leftsize -= root->leftsize + 1;//因为是原本的根节点被放到了右子树,且因为LL,根节点被放入了队列中,要把后续对leftsize的调整也减去。
}
//LR型:先对temp进行RR旋转,再对tempfu进行LL旋转(参数顺序可画图理解):
else
{
RR(false, NULL, n, temp, tempfu);
LL(true, temp, n, tempfu,tempfufu);
root->leftsize += root->leftchild->leftsize + 1;
root->rightchild->leftsize -= root->leftsize + 1;
}
root->color = 'b';
root->leftchild->color = root->rightchild->color = 'r';
}
//兄弟节点是红色时:变色不旋转,不旋转则leftsize可以不用变:
else
{
root->leftchild->color = root->rightchild->color = 'b';
}
}
//右子树:
else
{
//兄弟节点是黑色或者为空时:需要旋转
if (root->leftchild == NULL || root->leftchild->color == 'b')
{
//RR型:
if (n->data.first > temp->data.first)
{
RR(true, n, temp, tempfu, tempfufu);
}
//RL型:
else
{
LL(false, NULL, n, temp,tempfu);
RR(true, temp, n, tempfu, tempfufu);
}
root->leftsize += root->leftchild->leftsize+1;
root->color = 'b';
root->leftchild->color = root->rightchild->color = 'r';
}
//兄弟节点是红色时:变色不旋转,不旋转则leftsize可以不用变:
else
{
root->leftchild->color = root->rightchild->color = 'b';
}
}
}
else
{
//判断哪一边是兄弟:
if (temp->data.first < tempfu->data.first)
{
//对于兄弟节点为空或是黑色:需要旋转:
if (tempfu->rightchild == NULL || tempfu->rightchild->color == 'b')
{
//LL型:
if (n->data.first < temp->data.first)
{
LL(false, n, temp, tempfu,tempfufu);
if (tempfu->data.first > tempfufu->data.first)
{
tempfufu->rightchild->rightchild->leftsize -= tempfufu->rightchild->leftsize + 2;
}
else
{
tempfufu->leftchild->rightchild->leftsize -= tempfufu->leftchild->leftsize + 2;
}
}
//LR型:
else
{
RR(false, NULL, n, temp, tempfu);
LL(false, temp, n, tempfu,tempfufu);
if (n->data.first > tempfufu->data.first)
{
tempfufu->rightchild->leftsize += tempfufu->rightchild->leftchild->leftsize + 1;
tempfufu->rightchild->rightchild->leftsize-= tempfufu->rightchild->leftchild->leftsize + 2;
}
else
{
tempfufu->leftchild->leftsize += tempfufu->leftchild->leftchild->leftsize + 1;
tempfufu->leftchild->rightchild->leftsize -= tempfufu->leftchild->leftchild->leftsize + 2;//这些等式不要随意改,因为都是想好才写的
}
}
if (tempfu->data.first < tempfufu->data.first)
{
tempfufu->leftchild->color = 'b';
}
else
{
tempfufu->rightchild->color = 'b';
}
tempfufu->rightchild->leftchild->color = tempfufu->rightchild->rightchild->color = 'r';
}
//对于兄弟节点是红色的:变色不旋转,但需要回溯,注leftsize的调整只跟在旋转之后
else
{
tempfu->color = 'r';
tempfu->leftchild->color = tempfu->rightchild->color = 'b';
if (tempfufu->color == 'r')//表示其一定不是根节点,因为根节点是黑色的,所以可以寻找其父节点
{
note<k, t>* p = tempfufu->parent;
note<k, t>* pfu = p->parent;
if(pfu==NULL){
insertadjust(true, tempfu, tempfufu, p, pfu);
}
else {
insertadjust(false, tempfu, tempfufu, p, pfu);
}
}
}
}
else
{
//对于兄弟节点为空或是黑色:需要旋转:
if (tempfu->leftchild == NULL || tempfu->leftchild->color == 'b')
{
//RR型:对tempfu进行RR旋转
if (n->data.first > temp->data.first)
{
RR(false, n, temp, tempfu, tempfufu);
}
//RL型:对temp进行LL旋转,对tempfu进行RR旋转
else
{
LL(false, NULL, n, temp,tempfu);
RR(false, temp, n, tempfu, tempfufu);
if (tempfu->data.first < tempfufu->data.first)
{
tempfufu->leftchild->rightchild->leftsize--;
}
else
{
tempfufu->rightchild->rightchild->leftsize--;
}
}
if (tempfu->data.first < tempfufu->data.first)
{
tempfufu->leftchild->leftsize += tempfufu->leftchild->leftchild->leftsize + 1;
tempfufu->leftchild->color = 'b';
tempfufu->leftchild->leftchild->color = tempfufu->leftchild->rightchild->color = 'r';
}
else
{
tempfufu->rightchild->color = 'b';
tempfufu->rightchild->leftchild->color = tempfufu->rightchild->rightchild->color = 'r';
tempfufu->rightchild->leftsize += tempfufu->rightchild->leftchild->leftsize + 1;
}
}
//对于兄弟节点是红色的:变色不旋转,但需要递归回溯,注leftsize的调整只跟在旋转之后
else
{
tempfu->color = 'r';
tempfu->leftchild->color = tempfu->rightchild->color = 'b';
if (tempfufu->color == 'r')//表示其一定不是根节点,因为根节点是黑色的,所以可以寻找其父节点
{
note<k, t>* p = tempfufu->parent;
note<k, t>* pfu = p->parent;
if (pfu == NULL) {
insertadjust(true, tempfu, tempfufu, p, pfu);
}
else {
insertadjust(false, tempfu, tempfufu, p, pfu);
}
}
}
}
}
}
template<class k, class t>
void indexedRedBlackTree<k, t>::LL(bool isroot, note<k, t>* n, note<k, t>* temp, note<k, t>* tempfu,note<k, t>* tempfufu)
{ /*
函数作用:调整LL型,只负责旋转,不负责着色
参数:tempfu是否是根节点,插入的节点,插入节点的父节点temp,temp的父节点,temp的祖父节点
*/
if (isroot)
{
root = temp;
root->parent = NULL;//根节点的父节点为null,否则会陷入死循环
}
else
{
if (tempfu->data.first < tempfufu->data.first)//在左子树上
{
tempfufu->leftchild = temp;
}
else
{
tempfufu->rightchild = temp;
}
temp->parent = tempfufu;
}
if (temp->rightchild != NULL)
{
tempfu->leftchild = temp->rightchild;
tempfu->leftchild->parent = tempfu;
}
else {
tempfu->leftchild = NULL;
}
temp->rightchild = tempfu;
tempfu->parent = temp;
}
template<class k, class t>
void indexedRedBlackTree<k, t>::RR(bool isroot, note<k, t>* n, note<k, t>* temp, note<k, t>* tempfu,note<k, t>* tempfufu)
{ /*
函数作用:调整RR型,只负责旋转,不负责着色
参数:tempfu是否是根节点,插入的节点,插入节点的父节点temp,temp的父节点,temp的祖父节点
*/
if (isroot)
{
root = temp;
root->parent = NULL;
}
else
{
if (tempfu->data.first < tempfufu->data.first)
{
tempfufu->leftchild = temp;
}
else
{
tempfufu->rightchild = temp;
}
temp->parent = tempfufu;
}
if (temp->leftchild != NULL)
{
tempfu->rightchild = temp->leftchild;
tempfu->rightchild->parent = tempfu;
}
else {
tempfu->rightchild = NULL;
}
temp->leftchild = tempfu;
tempfu->parent = temp;
}
3.中序遍历输出:
template<class k, class t>
void indexedRedBlackTree<k, t>::ascend(note<k, t>* p)//递归中序输出:注递归的基础:基础条件,递归条件,不要写循环,因为递归本身就有循环的性质
{
if (p == NULL)
{
return;
}
ascend(p->leftchild);
cout << "(" << p->data.first << "," << p->data.second << "),颜色为" << p->color <<"索引为:"<<p->leftsize<< endl;
ascend(p->rightchild);
}
4.查询实现:
template<class k, class t>
t indexedRedBlackTree<k, t>::find(k key)
{
note<k, t>* temp = root;
while (temp != NULL)
{
if (key == temp->data.first)
{
return temp->data.second;
}
if (key < temp->data.first)
{
if (temp->leftchild == NULL)
{
cout << "对应节点不存在" << endl;
return NULL;
}
temp = temp->leftchild;
}
else
{
if (temp->rightchild == NULL)
{
cout << "对应节点不存在" << endl;
return NULL;
}
temp = temp->rightchild;
}
}
return NULL;
}
template<class k,class t>
pair<k,t>indexedRedBlackTree<k, t>::get(int index)//返回第index个数对
{
if (index < 0)
{
cout << "索引不可为负数" << endl;
throw _invalid_parameter;
}
note<k, t>* temp = root;
while (true)
{
if (index == temp->leftsize) //由此处判定从0开始计数
{
return temp->data;
}
if (index < temp->leftsize)
{
temp = temp->leftchild;
}
else
{
index -= temp->leftsize + 1;
if (temp->rightchild == NULL)//在左边的一定可以找到,右边的不一定
{
cout << "索引超出可查找范围" << endl;
throw _invalid_parameter;
}
temp = temp->rightchild;
}
}
}
5.删除实现:
template<class k,class t>
void indexedRedBlackTree<k, t>::deletekey(k key, t& x)
{
note<k, t>* temp = root;
note<k, t>* tempfu = root;
queue<note<k, t>*>q;
//寻找要删除的节点以及其父节点:
while (temp != NULL)
{
if (temp->data.first == key)
{
x = temp->data.second;
break;
}
else if (key < temp->data.first)
{
if (temp->leftchild == NULL)
{
cout << "未找到要删除的节点" << endl;
return;
}
q.push(temp); //因为删除需要维护leftsize
tempfu = temp;
temp = temp->leftchild;
}
else
{
if (temp->rightchild == NULL)
{
cout << "未找到要删除的节点" << endl;
return;
}
tempfu = temp;
temp = temp->rightchild;
}
}
deletecommon(temp, tempfu);
while (!q.empty())
{
note<k, t>* pp = q.front();
q.pop();
pp->leftsize--;
}
}
template<class k,class t>
void indexedRedBlackTree<k, t>::deletecommon(note<k, t>* temp,note<k, t>* tempfu)//此函数中有关旋转的后面需要进行调整
{ /*
函数作用:删除节点
参数:要删除的节点temp,删除节点的父节点
*///只有黑色叶节点的情况中跳出循环的情况需要调整左子域??
pair<k, t>w = temp->data;//用w保存真实删除节点的值
if (temp->color == 'r')
{
//删除红色叶节点:
if (temp->leftchild == NULL && temp->rightchild == NULL)
{
if (temp->data.first < tempfu->data.first)
{
tempfu->leftchild = NULL;
}
else
{
tempfu->rightchild = NULL;
}
}
//删除有两个孩子节点的红节点,要看替换节点的颜色:找到前驱节点进行替换
else if (temp->leftchild != NULL && temp->rightchild != NULL)
{ //对于左孩子节点的右子树为空的情况
if (temp->leftchild->rightchild == NULL)
{
if (temp->leftchild->leftchild != NULL) //直接把左孩子替换掉
{
temp->data = temp->leftchild->data;
temp->leftchild = temp->leftchild->leftchild;
temp->leftchild->color = 'b';
return;
}
else//即实际删除的是黑色的叶节点:需要回溯调整
{
w = temp->leftchild->data;
tempfu = temp;
temp = temp->leftchild;//需要进行后面的调整
}
}
//寻找左孩子的右子树中最右边的孩子节点:
else
{
note<k, t>* p2 = temp->leftchild;
note<k, t>* pfu = temp;
while (p2->rightchild != NULL)
{
pfu = p2;
p2 = p2->rightchild;
}
//替换:
temp->data = p2->data;
if (p2->color == 'r')
{
pfu->rightchild = NULL;
return;
}
else
{
if (p2->leftchild != NULL)
{
pfu->rightchild = p2->leftchild;
pfu->rightchild->color = 'b';
return;
}
else
{
tempfu = pfu;
temp = p2;//即实际删除的是黑色的叶节点
}
}
}
}
}
if (temp->color == 'b')//删除的是黑节点,此处不可改为else,因为前一个if如果没有return,则此处还可进行一次调整
{
//有两个子节点的:
if (temp->leftchild != NULL && temp->rightchild != NULL)
{
//是要找到替换节点,根据替换节点的颜色来判断是否需要继续调整
if (temp->leftchild->rightchild == NULL)
{
//红色节点:删了之后不用回溯
if (temp->leftchild->color == 'r')
{
temp->data = temp->leftchild->data;
if (temp->leftchild->leftchild != NULL)
{
temp->leftchild = temp->leftchild->leftchild;
}
else
{
temp->leftsize--;
temp->leftchild = NULL;
}
return;
}
//需要调整:结合此处的情况该删除的黑节点要么有一个左孩子(并且是红色),要么是一个叶节点
else
{
if (temp->leftchild->leftchild != NULL)
{
temp->data = temp->leftchild->data;
temp->leftchild = temp->leftchild->leftchild;
temp->leftchild->color = 'b';
return;
}
else
{
tempfu = temp;
w = temp->leftchild->data;//即实际删除的是黑色的叶节点
temp = temp->leftchild;//转移temp为真实要删除的目标,进行后面的调整
}
}
}
else
{
note<k, t>* p2 = temp->leftchild;
note<k, t>* pfu = temp;
while (p2->rightchild != NULL)
{
pfu = p2;
p2 = p2->rightchild;
}
temp->data = p2->data;
if (p2->color == 'r')//直接删了即可
{
temp->leftsize--;//此处做了修改
if (p2->leftchild != NULL)
{
pfu->rightchild = p2->leftchild;
}
else
{
pfu->rightchild = NULL;
}
return;
}
else
{
if (p2->leftchild != NULL)
{
pfu->rightchild = p2->leftchild;
pfu->rightchild->color = 'b';
return;
}
else
{
tempfu = pfu;
w = p2->data;
temp = p2;
}
}
}
}
//度=1:
if (temp->leftchild != NULL && temp->rightchild == NULL || temp->leftchild == NULL && temp->rightchild != NULL)
{//根据红黑树的性质,其有的那个子节点只可能是红色的
if (temp->data.first < tempfu->data.first)
{
if (temp->leftchild != NULL)
{
tempfu->leftchild = temp->leftchild;
}
else
{
tempfu->leftchild = temp->rightchild;
}
tempfu->leftchild->color = 'b';
}
else
{
if (temp->leftchild != NULL)
{
tempfu->rightchild = temp->leftchild;
}
else
{
tempfu->rightchild = temp->rightchild;
}
tempfu->rightchild->color = 'b';
}
}
//删除叶节点:
else if (temp->leftchild == NULL && temp->rightchild == NULL)
{
note<k, t>* begin = temp;
int change = 0;//用来记录进入下面的循环之后tempfu的是否发生了变化
//回溯:
while (begin->data.first != root->data.first)
{
if (begin->data.first <tempfu->data.first)//d为左节点
{
//情况1:兄弟节点为红色:
if (tempfu->rightchild->color == 'r')
{
tempfu->color = 'r';
tempfu->rightchild->color = 'b';
if (tempfu->data.first == root->data.first)
{
RR(true, tempfu->rightchild->rightchild, tempfu->rightchild, tempfu, tempfu);
}
else
{
note<k, t>* p = tempfu->parent;
RR(false, tempfu->rightchild->rightchild, tempfu->rightchild, tempfu, p);
}
continue;
}
//情况2:兄弟节点是黑色,远房侄子为红色:
else if (tempfu->rightchild->color == 'b' && tempfu->rightchild->rightchild != NULL && tempfu->rightchild->rightchild->color == 'r')
{
tempfu->rightchild->color = tempfu->color;
tempfu->color = 'b';
tempfu->rightchild->rightchild->color = 'b';
tempfu->leftchild = NULL;
if (tempfu->data.first == root->data.first)
{
RR(true, tempfu->rightchild->rightchild, tempfu->rightchild, tempfu, tempfu);
root->leftsize += root->leftchild->leftsize;//因为删除了一个节点就不加1了
root->leftchild->leftsize--;//因为删除了一个节点
}
else
{
note<k, t>* p = tempfu->parent;
RR(false, tempfu->rightchild->rightchild, tempfu->rightchild, tempfu, p);
note<k, t>* pp = tempfu->parent;
pp->leftsize += pp->leftchild->leftsize;
pp->leftchild->leftsize--;//因为删除了左边的一个节点
}
if (!change)
{
tempfu->data = w;
}
break;
}
//情况3:兄弟节点是黑色,近邻侄子为红色:
else if(tempfu->rightchild->color == 'b' && tempfu->rightchild->leftchild != NULL && tempfu->rightchild->leftchild->color == 'r')
{
//相当于RL型:
tempfu->rightchild->color = 'r';
tempfu->rightchild->leftchild->color = 'b';
LL(false, NULL, tempfu->rightchild->leftchild,tempfu->rightchild,tempfu );
tempfu->rightchild->color = tempfu->color;
tempfu->color = 'b';
tempfu->rightchild->rightchild->color = 'b';
tempfu->leftchild = NULL;
if (tempfu->data.first == root->data.first)
{
RR(true, tempfu->rightchild->rightchild, tempfu->rightchild, tempfu, tempfu);
}
else
{
note<k, t>* p = tempfu->parent;
RR(false, tempfu->rightchild->rightchild, tempfu->rightchild, tempfu, p);
}
//continue;
if (!change)
{
tempfu->data = w;
}//此处还需测试一下因为continue不用赋值,但break需要
break;
}
//情况4:父节点为红色,兄弟节点为黑色,且兄弟节点是叶节点:
else if (tempfu->color == 'r' && tempfu->rightchild->color == 'b' && tempfu->rightchild->leftchild == NULL && tempfu->rightchild->rightchild == NULL)
{
tempfu->leftchild = NULL;
tempfu->color = 'b';
tempfu->rightchild->color = 'r';
if (!change)
{
tempfu->data = w;
}
break;
}
if (!change)
{
tempfu->data = w;
}
change = 1;
begin = case5(begin); //前4种情况都不是,则调用第五种情况
tempfu = begin->parent;
continue;
}
else //右节点
{
//情况1:兄弟节点为红色:
if (tempfu->leftchild->color == 'r')
{
tempfu->color = 'r';
tempfu->leftchild->color = 'b';
if (tempfu->data.first == root->data.first)
{
LL(true, tempfu->leftchild->leftchild, tempfu->leftchild, tempfu, tempfu);
}
else
{
note<k, t>* p = tempfu->parent;
LL(false, tempfu->leftchild->leftchild, tempfu->leftchild,tempfu,p );
}
continue;
}
//情况2:兄弟节点是黑色,远房侄子为红色:
else if (tempfu->leftchild->color == 'b' && tempfu->leftchild->leftchild != NULL && tempfu->leftchild->leftchild->color == 'r')
{
tempfu->leftchild->color = tempfu->color;
tempfu->rightchild = NULL;
tempfu->leftchild->leftchild->color = 'b';
tempfu->color = 'b';
if (tempfu->data.first == root->data.first)
{
LL(true, tempfu->leftchild->leftchild, tempfu->leftchild, tempfu, tempfu);
root->leftchild->leftsize -= root->leftsize + 1;
}
else
{
note<k, t>* p = tempfu->parent;
LL(false, tempfu->leftchild->leftchild, tempfu->leftchild, tempfu,p );
note<k, t>* ofu = tempfu->parent;
tempfu->leftsize -= ofu->leftsize + 1;
}
if (!change)
{
tempfu->data = w;
}
break;
}
//情况3:兄弟节点是黑色,近邻侄子为红色:
else if (tempfu->leftchild->color == 'b' && tempfu->leftchild->rightchild != NULL && tempfu->leftchild->rightchild->color == 'r')
{
//相当于LR型,但可能和插入时一样,后一步操作需要把n和temp的位置交换
tempfu->leftchild->color = 'r';
tempfu->leftchild->rightchild->color = 'b';
RR(false, NULL, tempfu->leftchild->rightchild, tempfu->leftchild, tempfu);
tempfu->leftchild->color = tempfu->color;
tempfu->rightchild = NULL;
tempfu->leftchild->leftchild->color = 'b';
tempfu->color = 'b';
if (tempfu->data.first == root->data.first)
{
LL(true, tempfu->leftchild->leftchild, tempfu->leftchild, tempfu, tempfu);
}
else
{
note<k, t>* p = tempfu->parent;
LL(false, tempfu->leftchild->leftchild, tempfu->leftchild, tempfu,p );
}
if (!change)
{
tempfu->data = w;
}
break;
}
//情况4:父节点为红色,兄弟节点为黑色,且兄弟节点是叶节点:
else if (tempfu->color == 'r')
{
tempfu->rightchild = NULL;
tempfu->color = 'b';
tempfu->leftchild->color = 'r';
if (!change)
{
tempfu->data = w;
}
break;
}
//情况5:
if (!change)
{
tempfu->data = w;
}
change = 1;
begin = case5(begin);
tempfu = begin->parent;
continue;
}
}
}
}
}
template<class k, class t>
note<k, t>* indexedRedBlackTree<k, t>::case5(note<k, t>* d) //情况5:
{
note<k, t>* p = d->parent;
if (p->leftchild->data.first == d->data.first)
{
p->rightchild->color = 'r';
}
else
{
p->leftchild->color = 'r';
}
return p;
}
template<class k, class t>
void indexedRedBlackTree<k, t>::deleteindex(int index,pair<k,t>&x)
{
note<k, t>* temp = root;
note<k, t>* tempfu = root;
queue<note<k, t>*>q;
while (true)
{
if (temp->leftsize == index)
{
x = temp->data;
break;
}
if (index < temp->leftsize)
{
q.push(temp);
tempfu = temp;
temp = temp->leftchild;
}
else
{
index -= temp->leftsize + 1;
tempfu = temp;
if (temp->rightchild == NULL)
{
cout << "要删除的节点索引超出范围,删除失败" << endl;
return;
}
temp = temp->rightchild;
}
}
deletecommon(temp, tempfu);//参数为删除节点及其父节点
while (!q.empty())//对路径上的节点的左子域进行调整
{
note<k, t>* pp = q.front();
q.pop();
pp->leftsize--;
}
}
6.主函数测试:
int main()
{
int m,n,a,b,c; //c是用来输入操作序号的
cout << "此程序会根据输入整数n产生长度为n的随机序列并形成红黑树,请输入测试次数:";
cin >> m;
for (int q = 0; q < m; q++) {
cout<<"请输入n:";
cin >> n;
srand((unsigned int)time(0));
indexedRedBlackTree<int, char>rbt;
cout << "生成的随机序列如下:" << endl;
for (int i = 0; i < n; i++)
{
a= rand() % 100;
b = rand() % 123;
while (!(b >= 65 && b <= 90) && !(b >= 97 && b <= 122))
{
b = rand() % 123;
}
cout <<"("<< a << ',' << (char)b <<");";
pair<int, char>p(a, (char)b);
rbt.insert(p);
}
cout << "中序遍历生成的红黑树如下" << endl;
rbt.ascend(rbt.root);
while (true) {
cout << "查询操作输入1,删除操作输入2,停止此次测试输入-1:";
cin >> c;
if (c == -1) {
break;
}
else if (c == 1) {
while (true)
{
cout << "根据索引查询输入1;根据关键字查询输入2,停止查询输入-1:";
cin >> c;
if (c == -1) {
break;
}
else if (c == 1) {
cout << "请输入索引(整数序号,从0开始计数):";
cin >> c;
pair<int, char>k = rbt.get(c);
cout << "索引对应数对为" << k.first << ',' << k.second << endl;
}
else if (c == 2) {
cout << "请输入关键字(整数):";
cin >> c;
char a = rbt.find(c);
cout << "关键字对应的数据是:" << a << endl;
}
c = 0;//因为可能要查询的是-1;
}
}
else if (c == 2) {
char x;
pair<int, char> y;
while (c != -1)
{
cout << "根据关键字删除节点输入1;根据索引删除节点输入2;停止删除输入-1:";
cin >> c;
if (c == -1) {
break;
}
else if (c == 1)
{
cout << "请输入想删除的节点的关键字(整数):";
cin >> c;
rbt.deletekey(c, x);
cout << "所删除的关键字对应的数据是:" << x << endl;
cout << "删除后树的形态是:" << endl;
rbt.ascend(rbt.root);
}
else if (c == 2)
{
cout << "请输入想删除的节点的索引:";
cin >> c;
rbt.deleteindex(c, y);
cout << "所删除的索引对应的数据是:" << y.first << "," << y.second << endl;
cout << "删除后树的形态是:" << endl;
rbt.ascend(rbt.root);
}
c = 0;//因为可能要删除的是-1;
}
}
}
}
return 0;
}