深究map_set底层,探寻AVLTree与红黑树的秘密

一.二叉搜索树

  map_set的底层实现是一棵平衡二叉搜索树,在此之前先回顾一下啊二叉搜索树
  二叉搜索树的原理是,任意一个节点,其左子树的key值永远小于该节点的key值,而右子树的key值永远大于该节点的key值,树中不存在节点key值相等的情况。

1.二叉搜索树

1.插入

#include <iostream>
using namespace std;
template<class T>
class BSTreeNode {
public:
	BSTreeNode(const T& x):
		_left(nullptr),
		_right(nullptr),
		_val(x)
	{}
	BSTreeNode<T>* _left;
	BSTreeNode<T>* _right;
	T _val;

};
template <class T>
class BSTree{
public:
	typedef BSTreeNode<T> Node;
	BSTree() :
		_head(nullptr){}
	bool insert(const T& x) {                                //插入
		if (_head == nullptr) {
			_head = new Node(x);
			return true;
		}
		Node* cur = _head;
		Node* prev = nullptr;
		while (cur) {
			if (cur->_val == x) {
				return false;
			}
			else if (cur->_val < x) {
				prev = cur;
				cur = cur->_right;
			}
			else {
				prev = cur;
				cur = cur->_left;
			}
		}
		cur = new Node(x);
		prev->_val < x ? prev->_right = cur : prev->_left = cur;
	}
	private:
	Node* _head;
};

这是一个基本的二叉搜索树的创建。
  其中序遍历即是对这棵树的排序(由小到大):
因为中序遍历的本质就是先(递归左子树,访问该节点,递归右子树)。既然左子树小于该节点,那么遍历出来的左边都大于该节点,同理右子树都大于该节点,那么右边递归出来特都大于该节点。其本质有点类似 快速排序

2.删除

  平衡二叉树的删除有些许困难,需要删除且不改变树的结构。往前回顾,我们学的另一个树形结构——(优先级队列·priorty_queue)。堆这种结构的删除是通过将叶子节点换到该节点再进行操作,所以类比堆,我们以可以通过堆叶子节点的处理来进行删除。
请添加图片描述
找到左树的最右节点 或者 右树的最左节点进行替换即可
二叉搜索树的主要作用可以用于搜索,这样比顺序搜索效率更高,为 O(logN)

bool erase(const T& x) {
	Node* prev = nullptr;
	Node* cur = _head;
	while (cur) {
		if (cur->_val == x) {
			break;
		}
		else if (cur->_val < x) {
			prev = cur;
			cur = cur->_right;
		}
		else {
			prev = cur;
			cur = cur->_left;
		}
	}
	if (!cur) {//没找到
		return false;
	}
	else if (!(cur->_left && cur->_right)) {//有一个或没有子树
		Node* tmp = cur->_left ? cur->_left : cur->_right;
		if (prev) {
			// 将父节点的指针指向tmp
			(prev->_left == cur) ? prev->_left = tmp : prev->_right = tmp;
		}
		else {
			// 删除的是根节点,更新_head
			_head = tmp;
			delete cur;
		}
	}
	else {//两个子树
		Node* find = cur->_left;
		Node** find_prev = &(cur->_left);//Node** 负责记录关系
		while (find->_right) {
			find_prev = &(find->_right);
			find = find->_right;
		}
		cur->_val = find->_val;
		*find_prev = find->_left;//将删除的最右端的值与左侧相连
		delete find;
		return true;
	}
	
}

请添加图片描述

最右或最左 的时候链接不一定都是 left 或 right,故设置Node** 来代表指向的链接,这样在找到最左或最右的时候,直接 修改Node** 就可以避免 通过Node来找left或者right。

   二叉搜索树是有许多局限的,因为其不能保证此树的树形结构是否平衡
请添加图片描述
左边的搜索效率就不如右侧的搜索效率。故,存在一种新型的结构-平衡二叉搜索树

二.平衡二叉搜索树

1.AVLTree

  该结构由两位俄罗斯的数学家G.M.Adelson-Velskii和E.M.Landis在1962年,故称为AVLTree。其保证了二叉树在插入新结点的时候,保持每棵树的两个子树高度差不超过1。且是一个三叉链的结构,三叉链保证其能够进行旋转。

0.原理

  为了方便描述与判断,引入 平衡因子(Balance Factor) 概念,每一个节点都有一个平衡因子(平衡因子 = 左子树高度 - 右子树高度)当树的平衡因子 >=2||<=-2 时,代表此树已经出现不平衡的情况了。需要进行旋转调整。
  其插入与二叉搜索树大致相同,因为引入了平衡因子,多出了对平衡因子的改变和对树的旋转操作。

请添加图片描述
插入时一共有 3 种情况:

情况原因措施
1,-1插入前其父节点没有子树继续向上,直到找到平衡或者不平衡
0插入前其父节点只有一个子树,插入到父节点的空枝上无需往上,已经平衡
2,-2插入前其父节点只有一个子树,插入到唯一子树上无需往上,已经不平衡
bool insert(const pair<K, V>& kv) {
	Node* cur = _root;
	Node* parent = _root;
	if (_root == nullptr) {
		_root = new Node(kv);
		return true;
	}
	else {
		while (cur) {
			if (cur->_pair->first == kv.first)
				return false;
			else if (cur->_pair->first > kv.first) {
				parent = cur;
				cur = cur->_left;
			}
			else {
				parent = cur;
				cur = cur->_right;
			}
		}
		cur = new Node(kv);
		cur->_parent = parent;
		parent->_pair->first > kv.first ? parent->_left = cur : parent->_right = cur;//正常插入
	}
	//接下来对平衡因子进行调整
	while (parent) {//当cur走到头的时候停止
		cur == parent->_left ? parent->_Bf++ : parent->_Bf--;
		if (parent->_Bf==0) {
			break;
		}
		else if (parent->_Bf == -1 || parent->_Bf == 1) {
			cur = parent;
			parent = cur->_parent;
			continue;
		}
		else {//找到不平衡
			//进行旋转
		}
	}
}

以上代码并没有实现旋转的功能,
那么如何实现旋转呢?,共有两种旋转方式

1.单旋转

  当增加高度的树在同一侧时,可以进行单旋转
即将 “问题节点压下去,sub节点升起来,再对子树进行处理”。因为问题节点的左子树永远大于父亲节点,故可以交换。这是左单旋转,右单旋转与之类似

请添加图片描述
定义sub为问题节点的右节点(左单旋情况),问题节点为parent。

	void rotateL(Node* parent) {//左旋转
	Node* subR = parent->_right;
	Node* pparent = parent->_parent;
	if (pparent == nullptr) {
		_root = subR;
		subR->_parent = nullptr;
	}
	else {
		pparent->_left == parent ? pparent->_left = subR : pparent->_right = subR;
		subR->_parent = pparent;
	}
	parent->_right = subR->_left;
	if (subR->_left) {//当subR的左子树不为空时
		subR->_left->_parent = parent;
	}
	subR->_left = parent;
	parent->_parent = subR;
	parent->_Bf = subR->_Bf = 0;
}
void rotateR(Node* parent) {//右旋转
	Node* subL = parent->_left;
	Node* pparent = parent->_parent;
	if (pparent == nullptr) {
		_root = subL;
		subL->_parent = nullptr;
	}
	else {
		pparent->_left == parent ? pparent->_left = subL : pparent->_right = subL;
		subL->_parent = pparent;
	}
	parent->_left = subL->_right;
	if (subL->_right) {//当subL的右子树不为空时,用以判断右子树是否为nullptr
		subL->_right->_parent = parent;
	}
	subL->_right = parent;
	parent->_parent = subL;
	parent->_Bf = subL->_Bf = 0;
}

2.双旋转

  当增加高度的树并不在同一侧时,就无法单旋转了,此时需要进行双旋转。

请添加图片描述
       以左右双旋为例
请添加图片描述

  对3节点不在同侧的情况进行双旋转,该树的结构并不会发生改变。但是!!!,双旋转会改变平衡因子。所以不单单只是双旋转就结束,还要进行对平衡因子的改变。.
请添加图片描述
   当subLR的Bf是-1时,subL是1,parent是 0;
  当subLR的Bf是 1时,subL是0,parent是-1;
  当subLR的Bf是 0时,subL是0,parent是 0;

代码实现如下

void rotateRL(Node* parent) {
	Node* subR = parent->_right;
	Node* subRL = subR->_left;
	int BF = subRL->_Bf;
	rotateR(subR);
	rotateL(parent);
	switch (BF)
	{
	case(-1):
		parent->_Bf = 1;
		break;
	case(1):
		subR->_Bf = -1;
		break;
	case(0)://因为rotate已经把这三个节点搞成0了,所以只需要修改不是0的节点即可
		break;
	default:
		break;
	}
}
void rotateLR(Node* parent) {
	Node* subL = parent->_left;
	Node* subLR = subL->_left;
	int BF = subLR->_Bf;
	rotateL(subL);
	rotateR(parent);
	switch (BF)
	{
	case(-1):
		subL->_Bf = 1;
		break;
	case(1):
		parent->_Bf = -1;
		break;
	case(0):
		break;
	default:
		break;
	}
}

旋转完成后无需继续向上迭代,该子树已经回到插入前的高度

3.完整的AVLTree

完整的AVLTree实现如下:

using namespace std;
template<class K,class V>
class AVLTreeNode {
public:
	AVLTreeNode(const pair<K,V>& kv):
		_pair(kv),
		_parent(nullptr),
		_left(nullptr),
		_right(nullptr),
		_Bf(0)
	{}
	pair<K, V> _pair;
	AVLTreeNode* _parent;
	AVLTreeNode* _left;
	AVLTreeNode* _right;
	int _Bf;//balance factor
};
template<class K,class V>
class AVLTree {
public:
	typedef AVLTreeNode<K,V> Node;
	bool insert(const pair<K, V>& kv) {
		Node* cur = _root;
		Node* parent = _root;
		if (_root == nullptr) {
			_root = new Node(kv);
			return true;
		}
		else {
			while (cur) {
				if (cur->_pair.first == kv.first)
					return false;
				else if (cur->_pair.first > kv.first) {
					parent = cur;
					cur = cur->_left;
				}
				else {
					parent = cur;
					cur = cur->_right;
				}
			}
			cur = new Node(kv);
			cur->_parent = parent;
			parent->_pair.first > kv.first ? parent->_left = cur : parent->_right = cur;//正常插入
		}
		//接下来对平衡因子进行调整
		while (parent) {//当cur走到头的时候停止
			cur == parent->_left ? parent->_Bf++ : parent->_Bf--;
			if (parent->_Bf==0) {
				break;
			}
			else if (parent->_Bf == -1 || parent->_Bf == 1) {
				cur = parent;
				parent = cur->_parent;
				continue;
			}
			else {//找到不平衡
				//进行旋转
				if (parent->_Bf == 2) {
					if (cur->_Bf == 1) {
						rotateR(parent);//右单旋
					}
					else {//左右双旋转
						rotateLR(parent);
					}
				}
				else {
					if (cur->_Bf==-1) {
						rotateL(parent);
					}
					else {//右左双旋转
						rotateRL(parent);
					}
				}
				break;
			}
		}
	}
	void rotateL(Node* parent) {//左旋转
		Node* subR = parent->_right;
		Node* pparent = parent->_parent;
		if (pparent == nullptr) {
			_root = subR;
			subR->_parent = nullptr;
		}
		else {
			pparent->_left == parent ? pparent->_left = subR : pparent->_right = subR;
			subR->_parent = pparent;
		}
		parent->_right = subR->_left;
		if (subR->_left) {//当subR的左子树不为空时
			subR->_left->_parent = parent;
		}
		subR->_left = parent;
		parent->_parent = subR;
		parent->_Bf = subR->_Bf = 0;
	}
	void rotateR(Node* parent) {//右旋转
		Node* subL = parent->_left;
		Node* pparent = parent->_parent;
		if (pparent == nullptr) {
			_root = subL;
			subL->_parent = nullptr;
		}
		else {
			pparent->_left == parent ? pparent->_left = subL : pparent->_right = subL;
			subL->_parent = pparent;
		}
		parent->_left = subL->_right;
		if (subL->_right) {//当subL的右子树不为空时,用以判断右子树是否为nullptr
			subL->_right->_parent = parent;
		}
		subL->_right = parent;
		parent->_parent = subL;
		parent->_Bf = subL->_Bf = 0;
	}
	void rotateRL(Node* parent) {
		Node* subR = parent->_right;
		Node* subRL = subR->_left;
		int BF = subRL->_Bf;
		rotateR(subR);
		rotateL(parent);
		switch (BF)
		{
		case(-1):
			parent->_Bf = 1;
			break;
		case(1):
			subR->_Bf = -1;
			break;
		case(0)://因为rotate已经把这三个节点搞成0了,所以只需要修改不是0的节点即可
			break;
		default:
			break;
		}
	}
	void rotateLR(Node* parent) {
		Node* subL = parent->_left;
		Node* subLR = subL->_left;
		int BF = subLR->_Bf;
		rotateL(subL);
		rotateR(parent);
		switch (BF)
		{
		case(-1):
			subL->_Bf = 1;
			break;
		case(1):
			parent->_Bf = -1;
			break;
		case(0):
			break;
		default:
			break;
		}
	}
	void Inorder() {
		_Inorder(_root);
	}
	void _Inorder(Node* cur) {
		if (cur == nullptr) {
			return;
		}
		_Inorder(cur->_left);
		cout << cur->_pair.first << " : " << cur->_pair.second << endl;
		_Inorder(cur->_right);
	}
private:
	Node* _root=nullptr;
};

  AVLTree 的 一大优点就是其搜索效率极高达到 O(logn) ,但美中不足的是,他的插入效率并不高效,每一次插入都需要严格的遵守AVLTree的平衡原则。故出现了一种更高效的树形结构——红黑树。

2.RB_Tree(红黑树)

红黑树区别于AVLTree的一个关键点,就是其对于平衡条件不再过于苛刻了,其最终目的是:
  最长路径不超过最短路径的两倍

其要求为:
1.根节点必须是黑色。
2.叶子节点也是黑色。
3.红色节点的子节点是黑色。
4.任意节点的左右两树的任一路径上,黑色节点数量相同。
维护好以上关系,则此红黑树的最长路径永远也不会超过最短路径的两倍,
因为最短路径为全黑,最长路径为红黑交替,但黑色节点的个数不变,所以一定小于二倍。
在这里插入图片描述
  在插入的时候,我们通常将节点的初始颜色设定为红色,因为红节点相邻这条规则 比 黑节点在所有路径上的个数相同这条规则更好维护。

1.插入

插入的3种状况:

1.正常插入,此时插入节点的parent为黑色
2.插入时,相邻节点的颜色为红色,且uncle为红色
请添加图片描述
3.插入时,相邻节点颜色为红色,但uncle为黑色或不存在(因为uncle为黑色,所以不能贸然修改节点颜色)
  3.1 cur与parent呈直线型(单旋转)
请添加图片描述

  3.2 cur与parent呈折线型(双旋转)

请添加图片描述
在这里插入图片描述

bool insert(const pair<k,v>& pair) {
	if (_root == nullptr) {
		_root = new Node(pair);
		_root->_COL = co_BLACK;
		return true;
	}
	Node* cur = _root;
	Node* parent = _root;
	while (cur) {
		if (cur->_pair.first == pair.first) {
			return false;
		}
		else if (cur->_pair.first > pair.first) {
			parent = cur;
			cur = cur->_left;
		}
		else {
			parent = cur;
			cur = cur->_right;
		}
	}
	cur = new Node(pair);
	parent->_pair.first > pair.first ? parent->_left = cur : parent->_right = cur;
	cur->_parent = parent;
	//调整树的节点颜色
	//情况1:无事发生
	while (parent && parent->_COL == co_RED) {//当parent的节点的颜色与cur节点的颜色相同时
		Node* grand = parent->_parent;
		Node* uncle = (grand->_left == parent) ? grand->_right : grand->_left;
		if (uncle && uncle->_COL == co_RED) {//uncle存在,且uncle是红色
			grand->_COL = co_RED;
			parent->_COL = co_BLACK;
			uncle->_COL = co_BLACK;
			cur = grand;
			parent = cur->_parent;//调整完向上走
		}
		else{//uncle 不存在 或者 为黑色
			if(grand->_left==parent){//左树情况
				if (parent->_left != cur) {//此左右双旋,其实可以先 右单旋 再跟普通情况一起左单旋。
					rotateL(parent);
					swap(cur, parent);//把这两个指针的位置交换,这样才可以继续左单旋
				}
				rotateR(grand);
				//调整颜色
				parent->_COL = co_BLACK;
				grand->_COL = co_RED;
				break;
			}
			else {
				if (parent->_right != cur) {
					rotateR(parent);
					swap(cur, parent);//把这两个指针的位置交换,这样才可以继续左单旋
				}
				rotateL(grand);
				//调整颜色
				parent->_COL = co_RED;
				grand->_COL = co_RED;
				break;
			}
		}
	}
	_root->_COL = co_BLACK;
}
void rotateL(Node* parent) {//左单旋
	Node* grand = parent->_parent;
	Node* subR = parent->_right;
	Node* subRL = subR->_left;
	subR->_left = parent;
	if (_root == parent) {
		_root = subR;
		subR->_parent = nullptr;
	}
	else {
		grand->_left == parent ? grand->_left = subR : grand->_right = subR;
		subR->_parent = grand;
	}
	if (subRL != nullptr) {
		subRL->_parent = parent;
	}
	parent->_right = subRL;
	subR->_left = parent;
	parent->_parent = subR;
}
void rotateR(Node* parent) {//右单旋
	Node* grand = parent->_parent;
	Node* subL = parent->_left;
	Node* subLR = subL->_right;
	subL->_right = parent;
	if (_root == parent) {
		_root = subL;
		subL->_parent = nullptr;
	}
	else {
		grand->_left == parent ? grand->_left = subL : grand->_right = subL;
		subL->_parent = grand;
	}
	if (subLR != nullptr) {
		subLR->_parent = parent;
	}
	parent->_left = subLR;
	subL->_right = parent;
	parent->_parent = subL;
}

2.删除(******)

step1:按照二叉搜索树来进行删除
step2:红黑树的平衡调整
调整的n种情况:
ps:因为二叉搜索树对单链是直接删除,对双链是交换最右节点后删除(本质上还是单链删除),故只需讨论单链情况
永远只会出现以下情况:

删除节点为黑色,子节点为红,且只有一个子节点。(因为多一个红色,不满足红色不相邻;多一个黑色,不满足左右黑节点平衡)
删除节点为黑色,没有子节点
删除节点为黑色,没有子节点
请添加图片描述

1.删除节点为红色,则不改变。(红色不会改变红黑树的结构,每条路径的黑色节点任然不变)。
2.删除节点为黑色(绝对有兄弟,不然黑色节点不平衡)
  2.1删除节点的子节点颜色为红色,直接把子节点染黑。
在这里插入图片描述

为了方便描述和代码书写,接下来引入双黑节点

当一条支路需要多一个黑色节点时,将这条支路上的一个黑色节点置为黑色

  2.2兄弟节点为红色。

在这里插入图片描述

  2.3兄弟节点为黑色,兄弟节点的节点为红色

请添加图片描述
  2.4兄弟节点为黑色,兄弟节点的两个子节点为黑色请添加图片描述

代码如下:

void delete_Node(Node* cur) {
	Node* tmp = cur->_left ? cur->_left : cur->_right;
	Node* parent = cur->_parent;
	parent->_left == cur ? parent->_left = tmp : parent->_right = tmp;
}
void delete_adjust_dark(Node* cur) {//调整深黑(双黑)节点
	Node* parent = cur->_parent;
	if (cur->_COL == co_RED||_root==cur) {//若为根节点,双黑直接置黑色
		cur->_COL = co_BLACK;//若双黑节点为红色,直接置成黑色
	}
	else if (parent->_right == cur) {//双黑在右边情况
		Node* bro = parent->_left;
		if (bro->_COL == co_BLACK) {
			if (bro->_left && bro->_left->_COL == co_RED) {
				bro->_left->_COL = bro->_COL;
				bro->_COL = parent->_COL;
				parent->_COL = co_BLACK;//变色
				rotateR(parent);//旋转
			}
			else if (bro->_right && bro->_right->_COL == co_RED) {
				bro->_right->_COL = parent->_COL;
				parent->_COL = co_BLACK;
				rotateL(bro);
				rotateR(parent);
			}
			else {//兄弟节点有两个黑节点
				//双黑上移动+变色儿
				bro->_COL = co_RED;
				delete_adjust_dark(parent);
			}
		}
		else {//bro是红色
			bro->_COL = parent->_COL;
			parent->_COL = co_RED;
			rotateR(parent);
			delete_adjust_dark(cur);
		}
	}
	else {
		Node* bro = parent->_right;
		if (bro->_COL == co_BLACK) {
			if (bro->_right && bro->_right->_COL == co_RED) {
				bro->_right->_COL = bro->_COL;
				bro->_COL = parent->_COL;
				parent->_COL = co_BLACK;//变色
				rotateL(parent);//旋转
			}
			else if (bro->_left && bro->_left->_COL == co_RED) {
				bro->_left->_COL = parent->_COL;
				parent->_COL = co_BLACK;
				rotateR(bro);
				rotateL(parent);
			}
			else {//兄弟节点有两个黑节点
				//双黑上移动
				bro->_COL = co_RED;
				delete_adjust_dark(parent);
			}
		}
		else {//bro是红色
			bro->_COL = parent->_COL;
			parent->_COL = co_RED;
			rotateL(parent);
			delete_adjust_dark(cur);
		}
	}
}
bool erase(const k& key) {
	Node* parent = _root;
	Node* cur = _root;
	while (cur) {
		if (cur->_pair.first < key) {
			cur = cur->_right;
		}
		else if (cur->_pair.first > key) {
			cur = cur->_left;
		}
		else {
			break;
		}
	}
	if (cur == nullptr) {
		return false;
	}//step1:查找节点
	//step2:像二叉搜索树一般删除。
	if (!(cur->_left && cur->_right)) {
		Node* tmp = cur->_left ? cur->_left : cur->_right;
		if (_root == cur) {
			_root = tmp;
			tmp->_COL = co_BLACK;
			delete cur;
		}
		else {
			parent = cur->_parent;
			if (cur->_left || cur->_right) {//不会有双黑节点,直接将子节点颜色赋值为黑色
				cur->_left ? cur->_left->_COL = co_BLACK : cur->_right->_COL = co_BLACK;
			}
			else if(cur->_COL==co_BLACK){
				delete_adjust_dark(cur);//此时双黑节点是cur
			}//节点若为红色,直接删除
			delete_Node(cur);
		}
	}
	else {
		Node* find = cur->_left;
		while (find->_right) {
			find = find->_right;
		}
		cur->_pair = find->_pair;
		parent = find->_parent;
		if (find->_left || find->_right) {//不会有双黑节点的情况,直接将子节点颜色赋值为黑色
			find->_left ? find->_left->_COL = co_BLACK : find->_right->_COL = co_BLACK;
		}
		else if(find->_COL==co_BLACK){//双黑情况
			delete_adjust_dark(find);//此时双黑节点是find
		}//
		delete_Node(find);//删除前驱节点。
	}

}

  删除的操作比插入要困难许多,这种平衡二叉树的关键在于,先进行普通的搜索二叉树的删除操作,而后通过一系列的调整保证此树的结构不变。

3.模拟实现map_set

  在STL源码之中,map和set的底层都是红黑树,并且map和set都是对应同一棵红黑树,所以为了代码复用这里用到仿函数和另一种对键值对的处理方式。
  好比,RBTree< K, V , FUNC >

其中K是键,V是值,FUNC是从V中提炼K的仿函数。
这样在map中红黑树为,RBTree<K,pair<K,V>,Func>
在set中红黑树为,RBTree<K, K , Func>

  其次,还需要设计一个完善的iterator迭代器。此迭代器的本质其实是:

操作本质实现
operator++找到下一个比它大的最小元素右子树的最左节点(后继节点)
operator–找到上一个比它小的最大元素左子树的最右节点(前驱节点)

源码如下:

enum Node_COLOR1 {
	Node_RED1, Node_BLACK1
};

template<class T>
struct RBTreeNode {
	RBTreeNode(const T& x) :
		_left(nullptr),
		_right(nullptr),
		_parent(nullptr),
		_COL(Node_RED1),
		_data(x) {}
	RBTreeNode<T>* _left;
	RBTreeNode<T>* _right;
	RBTreeNode<T>* _parent;
	Node_COLOR1 _COL;
	T _data;
};

template<class T>
struct _TreeIterator {//迭代器启动!!!
	typedef RBTreeNode<T> Node;
	_TreeIterator(Node* node):
			_node(node){}
	typedef _TreeIterator<T> Self;
	Node* _node;
	Self& operator++() {//中序遍历的operator++,其本质其实是找到比它大的最小值
		if (_node == nullptr) { return *this; }
		if (_node->_right != nullptr) {
			_node = _node->_right;         // 进入右子树
			while (_node->_left != nullptr) {
				_node = _node->_left;      // 找到右子树的最左节点
			}
		}
		// 情况2:当前节点无右子树
		else {
			Node* parent = _node->_parent;
			// 向上回溯,直到找到第一个祖先节点,且当前节点是该祖先的左子节点
			while (parent != nullptr && _node == parent->_right) {
				_node = parent;
				parent = parent->_parent;
			}
			_node = parent; // 后继节点是父节点(可能为nullptr)
		}
		return *this;
	}
	Self& operator--() {
		if (_node == nullptr) return *this; // 边界情况

		// 情况1:当前节点有左子树
		if (_node->_left != nullptr) {
			_node = _node->_left;          // 进入左子树
			while (_node->_right != nullptr) {
				_node = _node->_right;     // 找到左子树的最右节点
			}
		}
		// 情况2:当前节点无左子树
		else {
			Node* parent = _node->_parent;
			// 向上回溯,直到找到第一个祖先节点,且当前节点是该祖先的右子节点
			while (parent != nullptr && _node == parent->_left) {
				_node = parent;
				parent = parent->_parent;
			}
			_node = parent; // 前驱节点是父节点(可能为nullptr)
		}
		return *this;
	}
	bool operator !=(const Self& other) const {
		return other._node!= _node;
	}
	T& operator*() {
		return _node->_data;
	}
	T* operator->() {
		return &(_node->_data);
	}
};

template<class k,class T,class KofT>
class RBTree {
	typedef RBTreeNode<T> Node;
public:
	typedef _TreeIterator<T> iterator;
	iterator begin() {
		Node* ret=_root;
		while (ret && ret->_left) {
			ret = ret->_left;
		}
		return iterator(ret);
	}
	iterator end() {
		return iterator(nullptr);
	}
	bool insert(const T& x) {
		if (_root == nullptr) {
			_root = new Node(x);
			_root->_COL = Node_BLACK1;
			return true;
		}
		KofT kofT;
		Node* cur = _root;
		Node* parent = _root;
		while (cur) {
			if (kofT(cur->_data) == kofT(x)) {
				return false;
			}
			else if (kofT(cur->_data) > kofT(x)) {
				parent = cur;
				cur = cur->_left;
			}
			else {
				parent = cur;
				cur = cur->_right;
			}
		}
		cur = new Node(x);
		kofT(parent->_data) > kofT(cur->_data) ? parent->_left = cur : parent->_right = cur;
		cur->_parent = parent;
		//调整树的节点颜色
		//情况1:无事发生
		while (parent && parent->_COL == Node_RED1) {//当parent的节点的颜色与cur节点的颜色相同时
			Node* grand = parent->_parent;
			Node* uncle = (grand->_left == parent) ? grand->_right : grand->_left;
			if (uncle && uncle->_COL == Node_RED1) {//uncle存在,且uncle是红色
				grand->_COL = Node_RED1;
				parent->_COL = Node_BLACK1;
				uncle->_COL = Node_BLACK1;
				cur = grand;
				parent = cur->_parent;//调整完向上走
			}
			else {//uncle 不存在 或者 为黑色
				if (grand->_left == parent) {//左树情况
					if (parent->_left != cur) {//此左右双旋,其实可以先 右单旋 再跟普通情况一起左单旋。
						rotateL(parent);
						swap(cur, parent);//把这两个指针的位置交换,这样才可以继续左单旋
					}
					rotateR(grand);
					//调整颜色
					parent->_COL = Node_BLACK1;
					grand->_COL = Node_RED1;
					break;
				}
				else {
					if (parent->_right != cur) {
						rotateR(parent);
						swap(cur, parent);//把这两个指针的位置交换,这样才可以继续左单旋
					}
					rotateL(grand);
					//调整颜色
					parent->_COL = Node_RED1;
					grand->_COL = Node_RED1;
					break;
				}
			}
		}
		_root->_COL = Node_BLACK1;
	}
	void rotateL(Node* parent) {//左单旋
		Node* grand = parent->_parent;
		Node* subR = parent->_right;
		Node* subRL = subR->_left;
		subR->_left = parent;
		if (_root == parent) {
			_root = subR;
			subR->_parent = nullptr;
		}
		else {
			grand->_left == parent ? grand->_left = subR : grand->_right = subR;
			subR->_parent = grand;
		}
		if (subRL != nullptr) {
			subRL->_parent = parent;
		}
		parent->_right = subRL;
		subR->_left = parent;
		parent->_parent = subR;
	}
	void rotateR(Node* parent) {//右单旋
		Node* grand = parent->_parent;
		Node* subL = parent->_left;
		Node* subLR = subL->_right;
		subL->_right = parent;
		if (_root == parent) {
			_root = subL;
			subL->_parent = nullptr;
		}
		else {
			grand->_left == parent ? grand->_left = subL : grand->_right = subL;
			subL->_parent = grand;
		}
		if (subLR != nullptr) {
			subLR->_parent = parent;
		}
		parent->_left = subLR;
		subL->_right = parent;
		parent->_parent = subL;
	}
	bool find(const k& key) {
		Node* cur = _root;
		KofT kofT;
		while (cur) {
			if (kofT(cur->_data)< key) {
				cur = cur->_right;
			}
			else if (kofT(cur->_data) > key) {
				cur = cur->_left;
			}
			else {
				return true;
			}
		}
		return false;
	}
	void delete_Node(Node* cur) {
		Node* tmp = cur->_left ? cur->_left : cur->_right;
		Node* parent = cur->_parent;
		parent->_left == cur ? parent->_left = tmp : parent->_right = tmp;
	}
	void delete_adjust_dark(Node* cur) {//调整深黑(双黑)节点
		Node* parent = cur->_parent;
		if (cur->_COL == Node_RED1 || _root == cur) {//若为根节点,双黑直接置黑色
			cur->_COL = Node_BLACK1;//若双黑节点为红色,直接置成黑色
		}
		else if (parent->_right == cur) {//双黑在右边情况
			Node* bro = parent->_left;
			if (bro->_COL == Node_BLACK1) {
				if (bro->_left && bro->_left->_COL == Node_RED1) {
					bro->_left->_COL = bro->_COL;
					bro->_COL = parent->_COL;
					parent->_COL = Node_BLACK1;//变色
					rotateR(parent);//旋转
				}
				else if (bro->_right && bro->_right->_COL == Node_RED1) {
					bro->_right->_COL = parent->_COL;
					parent->_COL = Node_BLACK1;
					rotateL(bro);
					rotateR(parent);
				}
				else {//兄弟节点有两个黑节点
					//双黑上移动+变色儿
					bro->_COL = Node_RED1;
					delete_adjust_dark(parent);
				}
			}
			else {//bro是红色
				bro->_COL = parent->_COL;
				parent->_COL = Node_RED1;
				rotateR(parent);
				delete_adjust_dark(cur);
			}
		}
		else {
			Node* bro = parent->_right;
			if (bro->_COL == Node_BLACK1) {
				if (bro->_right && bro->_right->_COL == Node_RED1) {
					bro->_right->_COL = bro->_COL;
					bro->_COL = parent->_COL;
					parent->_COL = Node_BLACK1;//变色
					rotateL(parent);//旋转
				}
				else if (bro->_left && bro->_left->_COL == Node_RED1) {
					bro->_left->_COL = parent->_COL;
					parent->_COL = Node_BLACK1;
					rotateR(bro);
					rotateL(parent);
				}
				else {//兄弟节点有两个黑节点
					//双黑上移动
					bro->_COL = Node_RED1;
					delete_adjust_dark(parent);
				}
			}
			else {//bro是红色
				bro->_COL = parent->_COL;
				parent->_COL = Node_RED1;
				rotateL(parent);
				delete_adjust_dark(cur);
			}
		}
	}
	bool erase(const k& key) {
		Node* parent = _root;
		Node* cur = _root;
		KofT kofT;
		while (cur) {
			if (kofT(cur->_data) < key) {
				cur = cur->_right;
			}
			else if (kofT(cur->_data) > key) {
				cur = cur->_left;
			}
			else {
				break;
			}
		}
		if (cur == nullptr) {
			return false;
		}//step1:查找节点
		//step2:像二叉搜索树一般删除。
		if (!(cur->_left && cur->_right)) {
			Node* tmp = cur->_left ? cur->_left : cur->_right;
			if (_root == cur) {
				_root = tmp;
				tmp->_COL = Node_BLACK1;
				delete cur;
			}
			else {
				parent = cur->_parent;
				if (cur->_left || cur->_right) {//不会有双黑节点,直接将子节点颜色赋值为黑色
					cur->_left ? cur->_left->_COL = Node_BLACK1 : cur->_right->_COL = Node_BLACK1;
				}
				else if (cur->_COL == Node_BLACK1) {
					delete_adjust_dark(cur);//此时双黑节点是cur
				}//节点若为红色,直接删除
				delete_Node(cur);
			}
		}
		else {
			Node* find = cur->_left;
			while (find->_right) {
				find = find->_right;
			}
			cur->_data = find->_data;
			parent = find->_parent;
			if (find->_left || find->_right) {//不会有双黑节点的情况,直接将子节点颜色赋值为黑色
				find->_left ? find->_left->_COL = Node_BLACK1 : find->_right->_COL = Node_BLACK1;
			}
			else if (find->_COL == Node_BLACK1) {//双黑情况
				delete_adjust_dark(find);//此时双黑节点是find
			}//
			delete_Node(find);//删除前驱节点。
		}

	}
	Node* _root = nullptr;
};


class map {
public:
	struct MapKeyOfT {
		K operator()(const pair<K, V>& kv) {
			return kv.first;
		}
	};
	typedef typename RBTree<K, pair<K, V>, MapKeyOfT>::iterator iterator;
	bool Insert(const pair<K, V>& _pair) {
		return _t.insert(_pair);
	}
	bool Erase(const K& x) {
		return _t.erase(x);
	}
	iterator begin() {
		return _t.begin();
	}
	iterator end() {
		return _t.end();
	}
private:
	RBTree<K,pair<K, V>,MapKeyOfT> _t;
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值