文章目录
一.二叉搜索树
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;
};