前言
这一篇博客我会给出AVL,红黑树,map和set的分装的代码
1. AVL树
//实现AVL树
template<class K>
struct BSNode
{
BSNode<K>* _left;
BSNode<K>* _right;
BSNode<K>* _parent;
int _bf;
K _key;
typedef BSNode<K> Node;
BSNode(const K& key)
:_key(key)
, _left(nullptr)
, _right(nullptr)
,_parent(nullptr)
,_bf(0)//右子树高度减左子树高度
{}
};
template<class K>
class BSTree
{
public:
typedef BSNode<K> Node;
bool insert(const K& key)
{
if (_root == nullptr)
{
_root = new Node(key);
return true;
}
Node* cur = _root;
Node* parent = nullptr;
while (cur)
{
if (key > cur->_key)
{
parent = cur;
cur = cur->_right;
}
else if (key < cur->_key)
{
parent = cur;
cur = cur->_left;
}
else
{
return false;
}
}
cur = new Node(key);
//但要注意_root==nullptr的时候
if (key > parent->_key)
{
parent->_right = cur;
cur->_parent = parent;
}
else
{
parent->_left = cur;
cur->_parent = parent;
}
//插入完成,开始检查是否平衡
while (cur!=_root)
{
//对于最初的和需要调整_bf的,遵循这个规则,插入右边,_bf就加加,插入左边就减减
if (parent->_left == cur)
{
parent->_bf--;
}
else if (parent->_right == cur)
{
parent->_bf++;
}
//如果parent的bf为0,就不用调整了//因为这个说明子树高度不变
if (parent->_bf == 0)
{
break;
}
//如果parent的bf为1,就要调整了,而且就是最初的那样调整//因为这个说明子树长高了
if (parent->_bf == -1 || parent->_bf == 1)
{
cur = parent;
if (parent->_parent)
{
parent = parent->_parent;
}
}
//这样就需要调整了
if (parent->_bf == -2 || parent->_bf == 2)
{
if (parent->_bf == 2 && cur->_bf == 1)//RR型
{
RR(parent);
}
else if (parent->_bf == -2 && cur->_bf == -1)//LL型
{
LL(parent);
}
else if (parent->_bf == 2 && cur->_bf == -1)//RL
{
RL(parent);
}
else if (parent->_bf == -2 && cur->_bf == 1)//LR
{
LR(parent);
}
else
{
assert(false);
}
break;//因为旋转之后高度降低了,或者说,高度恢复到以前的状态了,所以就平衡了,不用在调节了
//而删除就不一定了,因为本来就删除高度可能减了,旋转之后又减了,没有恢复到以前的状态,所以还可能多次旋转
}
}
return true;
}
//写个中序遍历
//_root是this指针里面的东西,所以不好搞,不好递归,所以采用调用函数的方法
void InOrder()
{
_InOrder(_root);
cout << endl;
}
void PreOrder()
{
_PreOrder(_root);
cout << endl;
}
//搜索某个数据
Node* Search(const K& key)
{
Node* cur = _root;
Node* parent = nullptr;
while (cur)
{
if (key > cur->_key)
{
parent = cur;
cur = cur->_right;
}
else if (key < cur->_key)
{
parent = cur;
cur = cur->_left;
}
else
{
return cur;
}
}
return nullptr;
}
//删除某个数据
bool Erase(const K& key)
{
if (_root == nullptr)
{
return false;
}
Node* cur = _root;
Node* parent = nullptr;
while (cur)
{
if (key > cur->_key)
{
parent = cur;
cur = cur->_right;
}
else if (key < cur->_key)
{
parent = cur;
cur = cur->_left;
}
else
{
//找到了要删除的数据
//删除的话就分为三种//
//第一种就是没有孩子直接删除
//第二种就是有一个孩子的话就直接连在父亲的后面
//第三种就是有两个孩子
//其中第一种和第二种可以合并。因为可以把没有孩子当做空指针的孩子
if (cur->_left == nullptr)
{
if (parent == nullptr)//说明删的是根
{
_root = cur->_right;
delete cur;
return true;
}
//先看cur在parent的左还是右
if (cur->_key < parent->_key)
{
parent->_left = cur->_right;
}
else
{
parent->_right = cur->_right;
}
delete cur;
return true;
}
else if (cur->_right == nullptr)
{
if (parent == nullptr)//说明删的是根
{
_root = cur->_left;
delete cur;
return true;
}
if (cur->_key < parent->_key)
{
parent->_left = cur->_left;
}
else
{
parent->_right = cur->_left;
}
delete cur;
return true;
}
else//现在左右孩子都不为空
{
//如果是头结点,也不用单独考虑,我们这样设计的话
//我们直接找到右孩子的最小值放在cur,然后删除这个最小值节点就可以了,最小值就是一直往左走就可以了
Node* min = cur->_right;
Node* min_parent = cur;
while (min->_left)
{
min_parent = min;
min = min->_left;
}
cur->_key = min->_key;
//删除min节点
//因为min的左孩子一定为空,所以很好删除
if (min_parent == cur)//说明没走
{
min_parent->_right = min->_right;
}
else
{
min_parent->_left = min->_right;
}
delete min;
return true;
}
}
}
return false;
}
bool IsBalance()
{
return _IsBalance(_root);
}
private:
void RR(Node* parent)
{
Node* parent_parent = parent->_parent;
Node* subR = parent->_right;
Node* subRL = subR->_left;
//开始链接左右孩子
parent->_right = subRL;
subR->_left = parent;
if (parent_parent)
{
if (parent_parent->_left == parent)
{
parent_parent->_left = subR;
}
else
{
parent_parent->_right = subR;
}
}
else//说明parent_parent是nullptr,parent就是_root了
{
_root = subR;
}
//开始链接父亲节点
if(subRL)//防止RL的时候调用为空,因为RL的时候调用的parent不是2或-2
subRL->_parent = parent;
parent->_parent = subR;
subR->_parent = parent_parent;
//开始修改_bf
parent->_bf = 0;
subR->_bf = 0;
}
void LL(Node* parent)//就是在RR的核心逻辑上right改left,left改right
{
Node* parent_parent = parent->_parent;
Node* subR = parent->_left;
Node* subRL = subR->_right;
//开始链接左右孩子
parent->_left = subRL;
subR->_right = parent;
if (parent_parent)
{
if (parent_parent->_left == parent)
{
parent_parent->_left = subR;
}
else
{
parent_parent->_right = subR;
}
}
else//说明parent_parent是nullptr,parent就是_root了
{
_root = subR;
}
//开始链接父亲节点
if(subRL)
subRL->_parent = parent;
parent->_parent = subR;
subR->_parent = parent_parent;
//开始修改_bf
parent->_bf = 0;
subR->_bf = 0;
}
void RL(Node* parent)
{
//先记录三个特殊的节点
Node* subR = parent->_right;
Node* subRL = subR->_left;
int tmp = subRL->_bf;
//这个的话,就是先将parent->right用LL处理,再用parent用RR处理
LL(parent->_right);
RR(parent);
//但是这样还不行,因为这样处理后全部的_bf都变为了0,这样是不行的,因为parent->right的_bf不为2或-2,所以这样处理会有问题
if (tmp == 0)//说明它没有孩子,如果有孩子的话,就插入不会不平衡
{
parent->_bf = 0;
subR->_bf = 0;
subRL->_bf = 0;
}
else if (tmp == -1)
{
parent->_bf = 0;
subR->_bf = 1;
subRL->_bf = 0;
}
else if (tmp == 1)
{
parent->_bf = -1;
subR->_bf = 0;
subRL->_bf = 0;
}
}
void LR(Node* parent)//还是一样的,right改left,left改right
{
//先记录三个特殊的节点
Node* subL = parent->_left;
Node* subLR = subL->_right;
int tmp = subLR->_bf;
//这个的话,就是先将parent->right用LL处理,再用parent用RR处理
RR(parent->_left);
LL(parent);
//但是这样还不行,因为这样处理后全部的_bf都变为了0,这样是不行的,因为parent->right的_bf不为2或-2,所以这样处理会有问题
//if (subLR->_bf == 0)//说明它没有孩子,如果有孩子的话,就插入不会不平衡
//还不能这样讨论,因为已经改为0了,应该提前记录
if(tmp==0)
{
parent->_bf = 0;
subL->_bf = 0;
subLR->_bf = 0;
}
else if (tmp == -1)
{
parent->_bf = 0;
subL->_bf = 1;
subLR->_bf = 0;
}
else if (tmp == 1)
{
parent->_bf = -1;
subL->_bf = 0;
subLR->_bf = 0;
}
}
void _InOrder(Node* root)
{
if (root == nullptr)
{
return;
}
_InOrder(root->_left);
cout << root->_key << " ";
_InOrder(root->_right);
}
void _PreOrder(Node* root)
{
if (root == nullptr)
{
return;
}
cout << root->_key << " ";
_PreOrder(root->_left);
_PreOrder(root->_right);
}
int GetHeight(Node*root)
{
if (root == nullptr)
{
return 0;
}
int h1 = GetHeight(root->_left);
int h2 = GetHeight(root->_right);
return h1 > h2 ? (h1 + 1) : (h2 + 1);
}
bool _IsBalance(Node* root)
{
if (root == nullptr)
{
return true;
}
//判断一个树是不是平衡树,先看这个节点的左右子树高度差绝对值是不是小于2,而且等于_bf
//然后就是左右子树均为平衡树
int h1 = GetHeight(root->_left);
int h2 = GetHeight(root->_right);
int dif = h2 - h1;
int BigDif = abs(dif);
if (BigDif >= 2 )
{
cout << "hahah" << endl;
return false;
}
if (dif != root->_bf)
{
cout << root->_bf << endl;
cout << dif << endl;
cout << root->_key << endl;
cout << "hhhh" << endl;
return false;
}
return _IsBalance(root->_left) && _IsBalance(root->_right);
}
Node* _root = nullptr;
};
2. 红黑树
enum color
{
Red,
Black
};
//实现AVL树
template<class K>
struct BRNode
{
BRNode<K>* _left;
BRNode<K>* _right;
BRNode<K>* _parent;
K _key;
color _color;
typedef BRNode<K> Node;
BRNode(const K& key)
:_key(key)
, _left(nullptr)
, _right(nullptr)
, _parent(nullptr)
,_color(Red)
{}
};
template<class K>
class BRTree
{
public:
typedef BRNode<K> Node;
bool insert(const K& key)
{
if (_root == nullptr)
{
_root = new Node(key);
_root->_color = Black;
return true;
}
Node* cur = _root;
Node* parent = nullptr;
while (cur)
{
if (key > cur->_key)
{
parent = cur;
cur = cur->_right;
}
else if (key < cur->_key)
{
parent = cur;
cur = cur->_left;
}
else
{
return false;
}
}
cur = new Node(key);
//但要注意_root==nullptr的时候
if (key > parent->_key)
{
parent->_right = cur;
cur->_parent = parent;
}
else
{
parent->_left = cur;
cur->_parent = parent;
}
//插入完成,开始检查是否平衡
while (parent&&parent->_color==Red)//红黑树总共有四个特性,
//左小于根小于右(左跟右),一条路黑相同(黑路同),根为黑(根叶黑),然后就是连续的不为红(不红红)
//插入只会不红红特性
{
//先找到叔叔parent->_color==Red说明一定有爷
Node* Grandparent = parent->_parent;
if (parent == Grandparent->_right)
{
//叔叔在左边
Node* uncle = Grandparent->_left;
//开始讨论叔叔为红还是黑//叔叔为空默认为黑
if (uncle && uncle->_color == Red)
{
//只需要将叔叔父亲变黑,爷爷变红就可以了
uncle->_color = Black;
parent->_color = Black;
Grandparent->_color = Red;
//然后将Grandparent看为cur继续循环
cur = Grandparent;
parent = cur->_parent;
//当parent为红就继续循环
//如果为空,说明cur为根,所以直接退出循环变黑,并增加条件parent不为空
}
else if (!uncle || uncle->_color == Black)//叔叔为空或者为黑//而且叔叔为黑这种情况只可能是由叔叔为红变过来的,不可能一开始插入就变成这样了
//因为不满足黑路同,所以cur还有子树,后面还有黑节点
{
//接下来就来看是什么类型的旋转
if (cur == parent->_right)//RR
{
RR(Grandparent);
//然后再让原来的爷爷变红,原来的父亲变黑,原来的父亲就变为爷爷
Grandparent->_color = Red;
parent->_color = Black;
//因为原来的父亲就变为爷爷,爷爷变黑,所以黑色节点每条路还是相同的,反正就是旋转之后就已经满足了红黑树了
//不需要在继续循环了
break;
}
else//RL
{
LL(parent);
RR(Grandparent);
//cur变黑,Grandparent变红
cur->_color = Black;
Grandparent->_color = Red;
break;
}
}
}
else
{
Node* uncle = Grandparent->_right;
//开始讨论叔叔为红还是黑//叔叔为空默认为黑
if (uncle && uncle->_color == Red)
{
//只需要将叔叔父亲变黑,爷爷变红就可以了
uncle->_color = Black;
parent->_color = Black;
Grandparent->_color = Red;
//然后将Grandparent看为cur继续循环
cur = Grandparent;
parent = cur->_parent;
//当parent为红就继续循环
//如果为空,说明cur为根,所以直接退出循环变黑,并增加条件parent不为空
}
else if (!uncle || uncle->_color == Black)//叔叔为空或者为黑//而且叔叔为黑这种情况只可能是由叔叔为红变过来的,不可能一开始插入就变成这样了
//因为不满足黑路同,所以cur还有子树,后面还有黑节点
{
//接下来就来看是什么类型的旋转
if (cur == parent->_left)//LL
{
LL(Grandparent);
//然后再让原来的爷爷变红,原来的父亲变黑,原来的父亲就变为爷爷
Grandparent->_color = Red;
parent->_color = Black;
//因为原来的父亲就变为爷爷,爷爷变黑,所以黑色节点每条路还是相同的,反正就是旋转之后就已经满足了红黑树了
//不需要在继续循环了
break;
}
else//LR
{
RR(parent);
LL(Grandparent);
//cur变黑,Grandparent变红
cur->_color = Black;
Grandparent->_color = Red;
break;
}
}
}
}
_root->_color = Black;
return true;
}
void InOrder()
{
_InOrder(_root);
cout << endl;
}
void PreOrder()
{
_PreOrder(_root);
cout << endl;
}
bool IsBalance()
{
return _IsBalance(_root);
}
//搜索某个数据
Node* Search(const K& key)
{
Node* cur = _root;
Node* parent = nullptr;
while (cur)
{
if (key > cur->_key)
{
parent = cur;
cur = cur->_right;
}
else if (key < cur->_key)
{
parent = cur;
cur = cur->_left;
}
else
{
return cur;
}
}
return nullptr;
}
//删除某个数据
bool Erase(const K& key)
{
if (_root == nullptr)
{
return false;
}
Node* cur = _root;
Node* parent = nullptr;
while (cur)
{
if (key > cur->_key)
{
parent = cur;
cur = cur->_right;
}
else if (key < cur->_key)
{
parent = cur;
cur = cur->_left;
}
else
{
//找到了要删除的数据
//删除的话就分为三种//
//第一种就是没有孩子直接删除
//第二种就是有一个孩子的话就直接连在父亲的后面
//第三种就是有两个孩子
//其中第一种和第二种可以合并。因为可以把没有孩子当做空指针的孩子
if (cur->_left == nullptr)
{
if (parent == nullptr)//说明删的是根
{
_root = cur->_right;
delete cur;
return true;
}
//先看cur在parent的左还是右
if (cur->_key < parent->_key)
{
parent->_left = cur->_right;
}
else
{
parent->_right = cur->_right;
}
delete cur;
return true;
}
else if (cur->_right == nullptr)
{
if (parent == nullptr)//说明删的是根
{
_root = cur->_left;
delete cur;
return true;
}
if (cur->_key < parent->_key)
{
parent->_left = cur->_left;
}
else
{
parent->_right = cur->_left;
}
delete cur;
return true;
}
else//现在左右孩子都不为空
{
//如果是头结点,也不用单独考虑,我们这样设计的话
//我们直接找到右孩子的最小值放在cur,然后删除这个最小值节点就可以了,最小值就是一直往左走就可以了
Node* min = cur->_right;
Node* min_parent = cur;
while (min->_left)
{
min_parent = min;
min = min->_left;
}
cur->_key = min->_key;
//删除min节点
//因为min的左孩子一定为空,所以很好删除
if (min_parent == cur)//说明没走
{
min_parent->_right = min->_right;
}
else
{
min_parent->_left = min->_right;
}
delete min;
return true;
}
}
}
return false;
}
private:
void RR(Node* parent)
{
Node* parent_parent = parent->_parent;
Node* subR = parent->_right;
Node* subRL = subR->_left;
//开始链接左右孩子
parent->_right = subRL;
subR->_left = parent;
if (parent_parent)
{
if (parent_parent->_left == parent)
{
parent_parent->_left = subR;
}
else
{
parent_parent->_right = subR;
}
}
else//说明parent_parent是nullptr,parent就是_root了
{
_root = subR;
}
//开始链接父亲节点
if (subRL)//防止RL的时候调用为空,因为RL的时候调用的parent不是2或-2
subRL->_parent = parent;
parent->_parent = subR;
subR->_parent = parent_parent;
}
void LL(Node* parent)//就是在RR的核心逻辑上right改left,left改right
{
Node* parent_parent = parent->_parent;
Node* subR = parent->_left;
Node* subRL = subR->_right;
//开始链接左右孩子
parent->_left = subRL;
subR->_right = parent;
if (parent_parent)
{
if (parent_parent->_left == parent)
{
parent_parent->_left = subR;
}
else
{
parent_parent->_right = subR;
}
}
else//说明parent_parent是nullptr,parent就是_root了
{
_root = subR;
}
//开始链接父亲节点
if (subRL)
subRL->_parent = parent;
parent->_parent = subR;
subR->_parent = parent_parent;
}
void _InOrder(Node* root)
{
if (root == nullptr)
{
return;
}
_InOrder(root->_left);
cout << root->_key << " ";
_InOrder(root->_right);
}
void _PreOrder(Node* root)
{
if (root == nullptr)
{
return;
}
cout << root->_key << " ";
_PreOrder(root->_left);
_PreOrder(root->_right);
}
bool _Judge1(Node* root, int min, int max)
{
if (root == nullptr)
{
return true;
}
if (!(root->_key >= min && root->_key <= max))
{
return false;
}
return _Judge1(root->_left, min, root->_key) && _Judge1(root->_right, root->_key, max);//往左走min保留,往右走max保留
}
bool Judge1(Node* root)
{
if (root == nullptr)
{
return true;
}
//这个就是判断一个树是不是搜索树罢了
//直接先序遍历,传入区间进去,值不满足上个父亲传下来的区间就是false
return _Judge1(root->_left,INT_MIN, root->_key) && _Judge1(root->_right, root->_key, INT_MAX);//这里的区间很难处理,所以我们
//定义一个很大的数,很很小的数
}
//bool Judge24(Node* root, int BlackNum, int num)
//{
// //我们用一个BlackNum来记录根节点到此节点的黑色节点数量
// //如何检验黑路同呢
// //对于一个节点来讲,它到任意叶子的黑色数量相同,然后左右子树也是这样,终止条件就是为null时,看数量是不是num
// if (root == nullptr)
// {
// if (num != BlackNum)
// {
// return false;
// }
// return true;
// }
// if (root->_color == Black)
// {
// BlackNum++;
// }
// return Judge24(root->_left, BlackNum, num) && Judge24(root->_right, BlackNum, num);
//}
// 或许我们可以这样理解,我们来实现一个先序遍历,一边遍历,一遍统计到此节点的黑色数量,到了空节点就判断一下,然后只要有一个地方不满足,就总的是
// false了,所以先序遍历间用的是&&
//然后我们在增加不红红的判断,就是在遍历的过程中看看如果自己为红,再看看父亲为不为红
bool Judge24(Node* root, int BlackNum, int num)
{
//我们用一个BlackNum来记录根节点到此节点的黑色节点数量
//如何检验黑路同呢
//对于一个节点来讲,它到任意叶子的黑色数量相同,然后左右子树也是这样,终止条件就是为null时,看数量是不是num
if (root == nullptr)
{
if (num != BlackNum)
{
return false;
}
return true;
}
if (root->_color == Black)
{
BlackNum++;
}
else
{
if (root->_parent && root->_parent->_color == Red)
{
return false;
}
}
return Judge24(root->_left, BlackNum, num) && Judge24(root->_right, BlackNum, num);
}
bool _IsBalance(Node* root)//这个函数来判断是不是红黑树
//红黑树总共有四个特性,挨个挨个判断就可以了
//左小于根小于右(左跟右),一条路黑相同(黑路同),根为黑(根叶黑),然后就是连续的不为红(不红红)
{
//根叶黑
if (_root->_color == Red)
{
return false;
}
//先统计好根到随便一个叶子结点的黑色节点数目
int num = 0;
Node * cur = _root;
while (cur)
{
if (cur->_color == Black)
{
num++;
}
cur = cur->_left;
}
return Judge24(root,0,num)&& Judge1(root);
}
Node* _root = nullptr;
};
3. map和set的分装
3.1 BRTree.h
namespace bit
{
enum color
{
Red,
Black
};
//实现AVL树
template<class T>//T可能是key也可能是pair
struct BRNode
{
BRNode<T>* _left;
BRNode<T>* _right;
BRNode<T>* _parent;
T _kv;
color _color;
BRNode(const T& kv)
:_kv(kv)
, _left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _color(Red)
{}
};
template<class T,class l1,class l2>
struct BRIterator
{
typedef BRIterator<T,l1,l2> self;
typedef BRNode<T> Node;
BRIterator(Node*tmp,Node*root)//C++中,构造函数的名字不可以是typedef出来的。所以不能用self的名字来构造
:_node(tmp)
,_root(root)
{}
self&operator++()
{
//找任意一个节点在中序遍历中的下一个节点,分为两种情况,有右子树,和没有右子树
if (_node->_right)
{
//就找右子树的最左边那个节点
Node* cur = _node->_right;
while (cur->_left)
{
cur = cur->_left;
}
_node = cur;
return *this;
}
else
{
//从该节点开始定义父节点和子节点,如果子节点是父节点的右孩子就继续往上找,左孩子就退出,并返回父节点
Node* cur = _node;
Node* parent = _node->_parent;
while (parent&& parent->_right == cur)//防止到了最后头结点
{
cur = parent;
parent = parent->_parent;
}
_node = parent;
return *this;
}
}
self& operator--()//这个与++就完全相反了,因为++是左中右,那么减减就是右中左,只需要左换右,右换左就可以了
{
//但万一_node是nullptr呢
if (_node == nullptr)
{
//直接让Node=end就可以了,就是最右边那个
//所以还要传入root
Node* cur = _root;
while (cur && cur->_right)
{
cur = cur->_right;
}
_node = cur;
return *this;
}
if (_node->_left)
{
//就找右子树的最左边那个节点
Node* cur = _node->_left;
while (cur&&cur->_right)
{
cur = cur->_right;
}
_node = cur;
return *this;
}
else
{
Node* cur = _node;
Node* parent = _node->_parent;
while (parent && parent->_left == cur)
{
cur = parent;
parent = parent->_parent;
}
_node = parent;
return *this;
}
}
l1 operator*()
{
return _node->_kv;
}
l2 operator->()
{
return &_node->_kv;
}
bool operator==(const self& se)
{
return _node == se._node;
}
bool operator!=(const self& se)//最好都写上const,因为end函数出来的是临时变量
{
return _node != se._node;
}
Node* _node;
Node* _root;
};
template<class K, class T,class KeyOfT>
class BRTree
{
public:
typedef BRNode<T> Node;
typedef BRIterator<T,T&,T*> self;
typedef BRIterator<T,const T&,const T*> const_self;
pair<self,bool> Insert(const T& kv)
{
if (_root == nullptr)
{
_root = new Node(kv);
_root->_color = Black;
return make_pair(self(_root,_root), true);
}
KeyOfT kof;
Node* cur = _root;
Node* parent = nullptr;
while (cur)
{
if (kof(kv) > kof(cur->_kv))//但是这里针对pair的比较又不行了,所以我们要改造函数//因为比较的是K
{
parent = cur;
cur = cur->_right;
}
else if (kof(kv) < kof(cur->_kv))
{
parent = cur;
cur = cur->_left;
}
else
{
return make_pair(self(cur,_root), false);
}
}
cur = new Node(kv);
Node* ret = cur;
//但要注意_root==nullptr的时候
if (kof(kv) > kof(parent->_kv))
{
parent->_right = cur;
cur->_parent = parent;
}
else
{
parent->_left = cur;
cur->_parent = parent;
}
//插入完成,开始检查是否平衡
while (parent && parent->_color == Red)//红黑树总共有四个特性,
//左小于根小于右(左跟右),一条路黑相同(黑路同),根为黑(根叶黑),然后就是连续的不为红(不红红)
//插入只会不红红特性
{
//先找到叔叔parent->_color==Red说明一定有爷
Node* Grandparent = parent->_parent;
if (parent == Grandparent->_right)
{
//叔叔在左边
Node* uncle = Grandparent->_left;
//开始讨论叔叔为红还是黑//叔叔为空默认为黑
if (uncle && uncle->_color == Red)
{
//只需要将叔叔父亲变黑,爷爷变红就可以了
uncle->_color = Black;
parent->_color = Black;
Grandparent->_color = Red;
//然后将Grandparent看为cur继续循环
cur = Grandparent;
parent = cur->_parent;
//当parent为红就继续循环
//如果为空,说明cur为根,所以直接退出循环变黑,并增加条件parent不为空
}
else if (!uncle || uncle->_color == Black)//叔叔为空或者为黑//而且叔叔为黑这种情况只可能是由叔叔为红变过来的,不可能一开始插入就变成这样了
//因为不满足黑路同,所以cur还有子树,后面还有黑节点
{
//接下来就来看是什么类型的旋转
if (cur == parent->_right)//RR
{
RR(Grandparent);
//然后再让原来的爷爷变红,原来的父亲变黑,原来的父亲就变为爷爷
Grandparent->_color = Red;
parent->_color = Black;
//因为原来的父亲就变为爷爷,爷爷变黑,所以黑色节点每条路还是相同的,反正就是旋转之后就已经满足了红黑树了
//不需要在继续循环了
break;
}
else//RL
{
LL(parent);
RR(Grandparent);
//cur变黑,Grandparent变红
cur->_color = Black;
Grandparent->_color = Red;
break;
}
}
}
else
{
Node* uncle = Grandparent->_right;
//开始讨论叔叔为红还是黑//叔叔为空默认为黑
if (uncle && uncle->_color == Red)
{
//只需要将叔叔父亲变黑,爷爷变红就可以了
uncle->_color = Black;
parent->_color = Black;
Grandparent->_color = Red;
//然后将Grandparent看为cur继续循环
cur = Grandparent;
parent = cur->_parent;
//当parent为红就继续循环
//如果为空,说明cur为根,所以直接退出循环变黑,并增加条件parent不为空
}
else if (!uncle || uncle->_color == Black)//叔叔为空或者为黑//而且叔叔为黑这种情况只可能是由叔叔为红变过来的,不可能一开始插入就变成这样了
//因为不满足黑路同,所以cur还有子树,后面还有黑节点
{
//接下来就来看是什么类型的旋转
if (cur == parent->_left)//LL
{
LL(Grandparent);
//然后再让原来的爷爷变红,原来的父亲变黑,原来的父亲就变为爷爷
Grandparent->_color = Red;
parent->_color = Black;
//因为原来的父亲就变为爷爷,爷爷变黑,所以黑色节点每条路还是相同的,反正就是旋转之后就已经满足了红黑树了
//不需要在继续循环了
break;
}
else//LR
{
RR(parent);
LL(Grandparent);
//cur变黑,Grandparent变红
cur->_color = Black;
Grandparent->_color = Red;
break;
}
}
}
}
_root->_color = Black;
return make_pair(self(ret, _root), true);
}
//搜索某个数据
Node* Search(const T& key)
{
KeyOfT kof;
Node* cur = _root;
Node* parent = nullptr;
while (cur)
{
if (kof(key) > kof(cur->_kv))
{
parent = cur;
cur = cur->_right;
}
else if (kof(key) < kof(cur->_kv))
{
parent = cur;
cur = cur->_left;
}
else
{
return cur;
}
}
return nullptr;
}
void InOrder()
{
_InOrder(_root);
cout << endl;
}
//迭代器
self Begin()
{
//找到最左边的节点就可以了
Node* cur = _root;
while (cur&&cur->_left)
{
cur = cur->_left;
}
return self(cur,_root);
}
self End()
{
return self(nullptr,_root);//我们以空指针作为end
}
const_self Begin()const
{
//找到最左边的节点就可以了
Node* cur = _root;
while (cur && cur->_left)
{
cur = cur->_left;
}
return const_self(cur, _root);
}
const_self End()const
{
return const_self(nullptr, _root);//我们以空指针作为end
}
private:
void RR(Node* parent)
{
Node* parent_parent = parent->_parent;
Node* subR = parent->_right;
Node* subRL = subR->_left;
//开始链接左右孩子
parent->_right = subRL;
subR->_left = parent;
if (parent_parent)
{
if (parent_parent->_left == parent)
{
parent_parent->_left = subR;
}
else
{
parent_parent->_right = subR;
}
}
else//说明parent_parent是nullptr,parent就是_root了
{
_root = subR;
}
//开始链接父亲节点
if (subRL)//防止RL的时候调用为空,因为RL的时候调用的parent不是2或-2
subRL->_parent = parent;
parent->_parent = subR;
subR->_parent = parent_parent;
}
void _InOrder(Node* root)
{
if (root == nullptr)
{
return;
}
_InOrder(root->_left);
KeyOfT k;
cout << k(root->_kv)<< " ";
//cout << root->_kv.first;//不能这样因为不知道kv是个啥
_InOrder(root->_right);
}
void LL(Node* parent)//就是在RR的核心逻辑上right改left,left改right
{
Node* parent_parent = parent->_parent;
Node* subR = parent->_left;
Node* subRL = subR->_right;
//开始链接左右孩子
parent->_left = subRL;
subR->_right = parent;
if (parent_parent)
{
if (parent_parent->_left == parent)
{
parent_parent->_left = subR;
}
else
{
parent_parent->_right = subR;
}
}
else//说明parent_parent是nullptr,parent就是_root了
{
_root = subR;
}
//开始链接父亲节点
if (subRL)
subRL->_parent = parent;
parent->_parent = subR;
subR->_parent = parent_parent;
}
Node* _root = nullptr;
};
}
3.2 set.h
namespace bit
{
template<class K>
class set
{
public:
struct KeyOf
{
K operator()(const K& k)
{
return k;
}
};
//typedef bit::BRIterator< K, const K&, const K*> iterator;
//typedef bit::BRIterator<K,const const K&,const const K*> const_iterator;
typedef typename bit::BRTree< K, const K, KeyOf>::const_self const_iterator;//这个要写typename,因为是在未实例化的模版里面用的变量
typedef typename bit::BRTree< K, const K, KeyOf>::self iterator;
void inorder()
{
_t.InOrder();
}
auto search(const K& k)
{
return _t.Search(k);
}
pair<iterator, bool> insert(const K& k)
{
return _t.Insert(k);
}
iterator begin()
{
return _t.Begin();
}
iterator end()
{
return _t.End();
}
const_iterator begin()const
{
return _t.Begin();
}
const_iterator end()const
{
return _t.End();
}
private:
BRTree< K,const K, KeyOf> _t;
};
void print(const set<int> s)
{
auto it = s.begin();
while (it != s.end())
{
cout << *it << " ";
++it;
}
cout << endl;
}
void test_set()
{
set<int> s;
s.insert(1);
s.insert(9);
s.insert(3);
s.insert(4);
s.insert(6);
s.insert(2);
s.insert(4);
/*auto p = s.search(4);
cout << p->_kv << endl;
s.inorder();*/
/*for (auto x : s)
{
cout << x << ' ';
}
cout << endl;
auto it = s.begin();
while (it != s.end())
{
cout << *it << " ";
++it;
}
cout << endl;
it = s.end();
while (it != s.begin())
{
--it;
cout << *it << " ";
}*/
print(s);
}
}
3.3 map.h
#pragma once
namespace bit
{
template<class K,class V>
class map
{
public:
struct KeyOf
{
K operator()(const pair<const K, V>& kv)
{
return kv.first;
}
};
//在这里也要写上const,因为k和v传过来,如果没写const,那么传进去,在传进去,里面的pair就是pair<K, V>,所以就很混乱
typedef bit::BRIterator<pair<const K, V>, pair<const K, V>&, pair<const K, V>*> iterator;
typedef bit::BRIterator<pair<const K, V>, const pair<const K, V>&,const pair<const K, V>*> const_iterator;
//K KeyOf(const pair<K, V>& kv)//函数定义在后面,前面要是用的话就要提前声明,但是这里比较麻烦,因为有两个
//{
// return kv.first;
//}
void inorder()
{
_t.InOrder();
}
pair<iterator, bool> insert(const pair<K, V>& kv)
{
return _t.Insert(kv);
}
iterator begin()
{
return _t.Begin();
}
iterator end()
{
return _t.End();
}
const_iterator begin()const
{
return _t.Begin();
}
V& operator[](const K& key)
{
//要调用insert
pair<iterator, bool> it=insert(make_pair(key, V()));//如果写pair的话就要说明类型,make_pair就不用说明类型了
//it.first这个是迭代器,在解引用就会得到pair<K, V>,或者>
return it.first->second;//
}
const_iterator end()const
{
return _t.End();
}
private:
BRTree<const K, pair<const K, V>, KeyOf> _t;//搜索树是不能修改key的
};
void test_map()
{
map<string, string> m;
m.insert(make_pair("eeeee", "aaaa"));
m.insert({ "cccc","aaaa" });
m.insert({ "aaaa","aaaa" });
m.insert({ "ddddd","aaaa" });
m.insert({ "aaaa","aaaa" });
m["mmmmm"] = "mmmmmm";
m["kkkkkkk"];
m["mmmmm"] = "2222";
m.inorder();
for (auto x : m)
{
//x.first += 'a';
cout << x.first << ' ';
}
cout << endl;
auto it = m.begin();
while (it != m.end())
{
cout << it->first << " " << it->second << endl;
++it;
}
cout << endl;
/*it = m.end();
while (it != m.begin())
{
--it;
cout << (*it).first << " ";
}*/
}
}
总结
下一篇我们讲哈希表