索引红黑树的插入和删除实现

思路:

(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;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值