红黑树的插入和删除完整代码

插入代码参考

红黑树的插入和删除完整代码

#include <iostream>
#include <cassert>
using namespace std;

enum colour {
	RED,//红色 默认为0
	BLACK,//黑色 默认为1
};
template<class K, class V>

struct  RBTreeNode {

	RBTreeNode<K, V> *_left;
	RBTreeNode<K, V> *_right;
	RBTreeNode<K, V> *_parent;
	pair<K, V> _kv;//当前节点值
	colour _col;//表示颜色

	RBTreeNode(const pair<K, V> &kv)
		: _left(nullptr),
		  _right(nullptr),
		  _parent(nullptr),
		  _kv(kv),
		  _col(RED) {
	}
};

template<class K, class V>

class RBTree {
		typedef RBTreeNode<K, V>  Node;
	public:
		bool insert(const pair<K, V> &kv) {
			if (_root == nullptr) {
				_root = new Node(kv);
				_root->_col = BLACK;//若刚插入一个节点,则该节点颜色是黑色
				return true;
			}
			Node *parent = nullptr;//用于记录cur的前一个节点
			Node *cur = _root;
			while (cur) {
				//若插入的值比当前树的值小 插入左边
				if (cur->_kv.first > kv.first) {
					parent = cur;
					cur = cur->_left;
				}
				//若插入的值比当前树的值大 插入右边
				else if (cur->_kv.first < kv.first) {
					parent = cur;
					cur = cur->_right;
				} else {
					//若插入的值,在树中有相同的值 ,则插入失败
					return false;
				}
			}
			cur = new Node(kv);
			//再次判断parent当前节点值与插入值大小
			if (parent->_kv.first > kv.first) {
				parent->_left = cur;
			} else {
				parent->_right = cur;
			}
			//cur的上一个节点即为 刚才的记录cur前一个节点的parent
			cur->_parent = parent;

			//当父节点不为NULL并且父节点为红色
			while (parent != nullptr && parent->_col == RED) {
				Node *grandfather = parent->_parent;//爷爷节点

				//若父节点为爷爷节点的左子树,则unlce为爷爷节点的右子树
				if (grandfather->_left == parent) {
					Node *uncle = grandfather->_right;
					//       g
					//    p     u
					// c
					//情况1:u存在并且为红,直接变色即可,并继续往上处理
					if (uncle && uncle->_col == RED)
						//若uncle节点为红色,将parent与uncle都置为黑色,爷爷节点置为红色
					{
						parent->_col = BLACK;
						uncle->_col = BLACK;
						grandfather->_col = RED;

						//继续往上调整
						cur = grandfather;
						parent = cur->_parent;
					}
					//情况2+3:u不存在或者u存在且为黑,旋转+变色
					else {
						//情况2
						//g p c 作为一条直线 所以为单旋
						//    g
						//  p   u
						//c
						if (cur == parent->_left) {
							//右旋转
							RotateR(grandfather);

							//最终p作为最终的根 为黑  g为红
							parent->_col = BLACK;
							grandfather->_col = RED;
						}
						//情况3
						//g p c 作为一条折线 所以为双旋
						//    g
						//   p   u
						//     c
						else {
							//左单旋
							RotateL(parent);
							//右单旋
							RotateR(grandfather);
							//最终cur作为最终的根 为黑  g为红
							cur->_col = BLACK;
							grandfather->_col = RED;
							//父节点继续保持红色
							parent->_col = RED;
						}
						break;
					}
				}

				else//grandfather->_right == parent
//					若父节点为爷爷节点的右子树,则unlce为爷爷节点的左子树
				{
					//   g
					// u   p
					//       c
					Node *uncle = grandfather->_left;

					//情况1:u存在并且为红,直接变色即可,并继续往上处理
					if (uncle && uncle->_col == RED)
						//若uncle节点为红色,将parent与uncle都置为黑色,爷爷节点置为红色
					{
						parent->_col = BLACK;
						uncle->_col = BLACK;
						grandfather->_col = RED;

						//继续往上调整
						cur = grandfather;
						parent = cur->_parent;
					}

					//情况2+3:u不存在或者u存在且为黑,旋转+变色
					else {
						//情况2
						//g p c 作为一条直线 所以为单旋
						//    g
						//  u   p
						//        c
						if (cur == parent->_right) {
							//左旋转
							RotateL(grandfather);

							//最终p作为最终的根 为黑  g为红
							parent->_col = BLACK;
							grandfather->_col = RED;
						}
						//情况3
						//g p c 作为一条折线 所以为双旋
						//   g
						//  u   p
						//    c
						else {
							//右单旋
							RotateR(parent);
							//左单旋
							RotateL(grandfather);
							//最终cur作为最终的根 为黑  g为红
							cur->_col = BLACK;
							grandfather->_col = RED;
						}
						break;
					}
				}
			}
			//为了避免grandfather节点正好为根时,会被更新成红色的情况
			_root->_col = BLACK;
			return true;
		}

		void inorder() { //中序遍历
			_inorder(_root);
			cout << endl;
		}
		//判断一颗二叉树是否为红黑树
		bool isbalance() {
			//检查根是否为黑
			if (_root && _root->_col == RED) {
				cout << "根节点颜色是红色" << endl;
				return false;
			}
			//连续的红色节点
			return _check(_root, 0);
		}

		bool _check(Node *root, int blacknum) {
			if (root == nullptr) {
				//为空时,blacknum代表一条路径的黑色节点个数
				cout << blacknum << " ";
				return true;
			}
			//blacknum代表黑色节点的个数
			if (root->_col == BLACK) {
				blacknum++;
			}
			//若当前节点为红 父节点也为红
			if (root->_col == RED
			        && root->_parent
			        && root->_parent->_col == RED) {
				cout << "存在连续的红色节点" << endl;
				return false;
			}
			//遍历整棵树
			return	_check(root->_left, blacknum) && _check(root->_right, blacknum);
		}
		void _inorder(Node *root) {
			if (root == nullptr) {
				return;
			}
			_inorder(root->_left);
			cout << root->_kv.first << " ";
			_inorder(root->_right);
		}
		void RotateL(Node *parent) { //左单旋
			Node *subR = parent->_right;
			Node *subRL = subR->_left;

			parent->_right = subRL;
			if (subRL != nullptr) {
				subRL->_parent = parent;
			}
			Node *ppnode = parent->_parent;//记录parent的前一个节点

			subR->_left = parent;
			parent->_parent = subR;

			if (ppnode == nullptr) { //说明parent是根即代表整棵树
				_root = subR;//subR作为新的根
				_root->_parent = nullptr;//subR的父节点指向原来的parent,所以要置nullptr
			} else { //说明旋转的是一部分,所以要跟ppnode相连接
				if (ppnode->_left == parent) { //若连接在左子树上
					ppnode->_left = subR;
				} else { //若连接在右子树上
					ppnode->_right = subR;
				}
				subR->_parent = ppnode;//将subR父节点置为ppnode
			}
		}

		void RotateR(Node *parent) { //右单旋
			Node *subL = parent->_left;
			Node *subLR = subL->_right;
			parent->_left = subLR;
			if (subLR != nullptr) {
				subLR->_parent = parent;
			}
			Node *ppnode = parent->_parent;//记录parent的父节点
			subL->_right = parent;
			parent->_parent = subL;

			if (ppnode == nullptr) { //若旋转整棵树
				_root = subL;
				_root->_parent = nullptr;
			} else { //若旋转整棵树的部分子树
				if (ppnode->_left == parent) {
					ppnode->_left = subL;
				} else {
					ppnode->_right = subL;
				}
				subL->_parent = ppnode;//使subL的父节点为ppnode
			}

		}
		bool deleteNode (const int key) {
			if (_root == nullptr) {
				cout << "没有节点" << endl;
				return false;
			}
			Node *cur = _root;
			while (cur) {
				if (cur->_kv.first > key) {
					//往左子树查找
					cur = cur->_left;
				} else if (cur->_kv.first < key) {
					//往右子树查找
					cur = cur->_right;
				} else {
					//已经查找完毕
					break;
				}
			}
			if (cur == nullptr) {
				//指向方形叶节点,表明查找失败
				cout << "删除失败,未查找到" << endl;
				return false;
			}
			while (cur) {


				Node *parent = cur->_parent;


				//删除的为黑色节点
				Node *subL = cur->_left;
				Node *subR = cur->_right;
				if ((subL && subL->_col == RED && subR == nullptr) || (subL && subL->_col == RED && subR && subR->_col == RED)) {
					//左红孩,右黑孩,左右红孩
					//如果只有一个孩子,则必然是红孩子,在左子树则向上替换后变黑
					cur->_kv.first = subL->_kv.first;
					cur->_left = nullptr;
					delete (subL);
					return true;
				} else if (subR && subL == nullptr) {
					//如果只有一个右孩子
					cur->_kv.first = subR->_kv.first;
					cur->_right = nullptr;
					delete (subR);
					return true;
				} else if (subL && subR) {
					//如果有两个孩子
					//有限选择使用第一个后继节点替换
					Node *firstbehind = cur->_left;
					while (firstbehind->_right) {
						firstbehind = firstbehind->_right;
					}
					cur->_kv = firstbehind->_kv;
					cur = firstbehind;
					//继续循环
				} else if (subL == nullptr && subR == nullptr) {
					//没有孩子
					if (cur->_col == RED) {
						//如果删除的为红色节点,则不需要调节平衡树
						if (parent->_left == cur) {
							//在左子树,释放父节点左子树
							parent->_left = nullptr;
						} else {
							//在右子树,释放父节点右子树
							parent->_right = nullptr;
						}
						delete (cur);
						return true;
					} else {
						//删除的是黑色节点
						//没有父节点则为根节点


						if (parent == nullptr) {
							delete (cur);
							_root = nullptr;
							return true;
						}
						//有父节点则一定有叔叔节点
						Node *uncle = nullptr;
						//使用删除标志,只删除一次节点
						bool is_delete = false;
						while (cur) {
							parent = cur->_parent;
							if (parent == nullptr) {
								//无父亲则跳出循环,说明多次迭代以达到根节点
								return true;
							}
							//多次迭代还有父亲,就要继续迭代
							if (cur == parent->_right) {
								if (is_delete == false) {
									//只删除一次
									parent->_right = nullptr;
									delete (cur);
									is_delete = true;
								}
								//叔叔在左子树
								uncle = parent->_left;
								//叔叔至少有一个红孩子
								//红孩子在左子树
								Node *uncleL = uncle->_left;
								Node *uncleR = uncle->_right;
								if (uncle->_col == BLACK) {
									//叔叔存在且颜色为黑色
									if (uncleL && uncleL->_col == RED) {
										//判断条件为左边为红孩子,右边可以不是红孩子(为空黑)
										//因为叔叔是黑色的,想办法将父亲的颜色和叔叔的颜色交换
										//这样能够保持父亲右旋时,叔叔右孩子上面的颜色序列与原先一致
										//现在还需要保持叔叔左孩子的上面的颜色序列与原先一致,因为左孩子为红
										//所以其上面的颜色序列决定于叔叔和父亲。只要让红孩子继承叔叔的颜色即可
										//相当于uncleL=uncle,parent<=>uncle=黑,parent右旋
										uncleL->_col = uncle->_col;
										colour tempcolor = uncle->_col;
										uncle->_col = parent->_col;
										parent->_col = tempcolor;
										//右旋父亲
										RotateR(parent);
										//因为根节点颜色没有发生改变,所以不用向上检查
										return true;
									} else if (uncleL == nullptr && uncleR && uncleR->_col == RED) {
										//只有右边有红孩子
										//红孩子的上层颜色序列取决于叔叔和父亲,叔叔的上层颜色序列取决于父亲
										//uncle左旋会导致uncleR的右孩子无法吃到s的加层,因此要么改变父亲的颜色为叔叔
										//要么改变uncleR的颜色为叔叔,因为父亲要变成黑色节点用来补充双黑节点
										//而uncle的颜色为黑色,相当于父亲颜色变成叔叔,这样父亲右旋时
										//uncleR的有孩子可以吃到s的加成,但这样会导致叔叔和uncleR吃不到父亲的颜色加成
										//于是可以把uncleR的颜色替换为父亲的颜色
										//相当于uncleR=parent,parent=uncle=黑,uncle左旋,parent右旋
										uncleR->_col = parent->_col;
										parent->_col = BLACK;
										RotateL(uncle);
										RotateR(parent);
										//因为根节点颜色没有发生改变,所以不用向上检查
										return true;
									} else {
										//叔叔节点的有两个黑孩子,叔叔变红,如果父亲为红则变黑,否则cur指向父亲,向上检查
										uncle->_col = RED;
										if (parent->_col == RED) {
											parent->_col = BLACK;
											return true;
										} else {
											cur = parent;
										}
									}
								} else {
									//叔叔为红色,uncleR,uncleL,uncle取决于parent颜色,因为uncleR必为黑色,parent右旋能够得到黑补偿,uncleL能够吃到parent的黑
									//唯一受到影响的是uncleR无法吃到uncle的颜色序列,parent交换颜色后右旋保证了的uncleR的颜色序列依然是一样的
									//因为parent=黑,uncle=红,所以直接赋值parent=红,uncle=黑,parent右旋
									parent->_col = RED;
									uncle->_col = BLACK;
									RotateR(parent);
									//因为根节点颜色为u变化,所以不向上检查
									return true;

								}
							} else {
								if (is_delete == false) {
									parent->_left = nullptr;
									delete (cur);
									is_delete = true;
								}
								//叔叔在右子树
								uncle = parent->_right;
								Node *uncleL = uncle->_left;
								Node *uncleR = uncle->_right;

								if (uncle && uncle->_col == BLACK) {
									//叔叔为黑色
									if (uncleR && uncleR->_col == RED) {
										uncleR->_col = uncle->_col;
										colour tempcolor = uncle->_col;
										uncle->_col = parent->_col;
										parent->_col = tempcolor;
										RotateL(parent);
										return true;
									} else if (uncleR == nullptr && uncleL && uncleL->_col == RED) {
										//uncleL=parent,parent=uncle=黑,uncle右旋,parent左旋
										uncleL->_col = parent->_col;
										parent->_col = uncle->_col;
										RotateR(uncle);
										RotateL(parent);
										//根节点颜色没有发生改变,不用向上检查
										return true;
									} else {
										uncle->_col = RED;
										if (parent->_col == RED) {
											parent->_col = BLACK;
											return true;
										} else {
											cur = parent;
										}
									}
								} else {
									//叔叔为红色
									parent->_col = RED;
									uncle->_col = BLACK;
									RotateL(parent);
									return true;

								}

							}
						}
					}
				}
			}
			return true;
		}




	private:
		Node *_root = nullptr;
};


void test_RBTree1() {

	int a[] = {16, 3, 7, 11, 9, 26, 18, 14, 15};
	//int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16,14 };
	RBTree<int, int>v1;
	for (auto e : a) {
		v1.insert(make_pair(e, e));
	}
	v1.inorder();
	cout << v1.isbalance() << endl;
	while (1) {
		int temp;
		cin >> temp;
		v1.deleteNode(temp);
		v1.inorder();
	}


}

int main() {
	test_RBTree1();

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值