Use set
Set简介:具有指定顺序的容器,不允许修改节点的值,可以插入或者删除节点的值,根据Compare来比较(compare是内部仿函数,默认是严格的小于)。(底层是红黑树)
介绍几个关键的:
find:find会在set里面去寻找相同的节点,若找到,则返回指其的iterator(迭代器),没找到返回end(),也是迭代器。
erase:如下图,有三种情况,删除某迭代器指定位置,删除某个值,删除某段迭代器区间。
iterator erase (const_iterator position);
如果没有这个位置,程序会直接崩掉
返回值是删除的节点的下一个节点
如果删除的是最后一个就返回end()
size_type erase (const value_type& val);
返回成功删除的值的个数
iterator erase (const_iterator first, const_iterator last);
删除迭代器区间
返回值是删除的最后一个节点的下一个节点
如果删除的是最后一个就返回end()
loewr_bound:返回一个迭代器,其指向的相等或者之后的。(默认情况的严格小于排序就是>=,有闭区间那意思),意思就是说,可以给一个值位于其存在的区间之间,返回下一个值。
例:已经插入的值 :2,10,20
结果就是:lower_bound(8) == 10
iterator lower_bound (const value_type& val);
const_iterator lower_bound (const value_type& val) const;
upper_bound:返回一个迭代器,其指向于val之后的一个值(有开区间那味道)
例子:插入值为12,20,30
upper_bound(20)
upper_bound(21)
默认情况下:上面两个结果都是30
iterator upper_bound (const value_type& val);const_iterator upper_bound (const value_type& val) const;
equal_range:返回迭代器区间,对这个区间左闭有开的看法,必然包含val这个元素。不代表对迭代器遍历就会有这个元素,只是返回区间包含。
pair<const_iterator,const_iterator> equal_range (const value_type& val) const;pair<iterator,iterator>
测试代码:
void test_1()
{
set<int> s;//random number test
s.insert(5);
s.insert(1);
s.insert(1);//值已经有了,就不会再插入//通过键值对绑定一个bool值来实现
s.insert(1);
s.insert(3);
s.insert(2);
s.insert(4);
s.insert(6);
set<int>::iterator it = s.begin();
while(it!=s.end())
{
cout<<*it<<" ";
it++;
}
cout<<endl;
it = s.find(2);
if(it!=s.end())
{
s.erase(it);
}
// s.erase(it);//给迭代器的话,删除的值不存在程序会直接崩溃
cout<<s.erase(2);//直接erase,某个值,就算不存在,就会返回一些值。返回删除该值的个数
cout<<endl;
for(auto num:s)
{
cout<<num<<" ";
}
cout<<endl;
return ;
}
void test_2()
{
set<int> s;
for(int i=0;i<10;i++){
s.insert(i*10);
}
auto itlow = s.lower_bound(25);
auto itup = s.upper_bound(70);//这里返回的是实际比70大的下一个值的迭代器
// cout<<*itup<<endl;//这里打印的值就是80
s.erase(itlow,itup);//删除这段区间的值,而且删除的是闭区间,
for(auto num:s)
{
cout<<num<<" ";
}
cout<<endl;
}
void test_3()
{
set<int> s;
for(int i=0;i<10;i++){
s.insert(i*10);
}
pair<set<int>::iterator,set<int>::iterator> ret = s.equal_range(20);//找到相等的值,返回相等的值开始及其下一个区间
ret =s.equal_range(35);//这里返回的是大于当前值的下一个值。
cout<<*(ret.first)<<" "<<*(ret.second)<<endl;
}
void test_Mutiset()
{
multiset<int> s;//其就是底层的pair不再是bool值,而是变成了其他的计数类型
s.insert(5);
s.insert(1);
s.insert(2);
s.insert(2);
s.insert(2);
s.insert(4);
s.insert(6);
auto it = s.find(2);
while(it!=s.end()){
cout<<*it<<' ';
it++;
}
cout<<endl;
cout<<s.erase(2)<<endl;//显示了成功删除的个数
pair<multiset<int>::iterator,multiset<int>::iterator> ret = s.equal_range(2);//对于mutiset,就会返回set
while(ret.first!=ret.second)
{
cout<<*ret.first;
s.erase(ret.first++);
}
cout<<endl;
return ;
}
Use map
Map是一种映射,存在key value 和mapped value之间存在映射(就像函数一样),允许使用“ [] ”来通过key值去访问映射值,底层是二叉搜索树。
其他的使用基本都和set是一样的。
着重讲一下 []的
其实现是
(*((this->insert(make_pair(k,mapped_type()))).first))
((this->insert(make_pair(k,mapped_type()))).first)
*((this->insert(make_pair(k,mapped_type())))
(this->insert(make_pair(k,mapped_type()))
this->insert(make_pair(k,mapped_type())
再来看看insert,意思就是说成功,返回插入的值的迭代器指向的第一个元素,如果有,返回已有迭代器。
The single element versions (1) return a pair, with its member
pair::first set to an iterator pointing to either the newly inserted
element or to the element with an equivalent key in the map. The
pair::second element in the pair is set to true if a new element was
inserted or false if an equivalent key already existed.
测试代码:
void test_map2(){
string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜","苹果", "香蕉", "苹果", "香蕉" };
map<string, int> m;
for(auto& str:arr)
{
// auto it = m.find(str);
// if(it == m.end())//没有这个元素
// {
// m.insert(make_pair(str,1));
// continue;
// }
// else
// {
// it->second++;
// }
m[str]++;//在map里面,提供了[]的接口,可以替代上面
//其底层实际就是调用了一次insert
//(*((this->insert(make_pair(k,mapped_type()))).first)).
//有了,那个key值,就会插入失败,并且对当前节点修改
//这表征了,如果再次插入相同的值,map就不会再多
//mutimap就可以可以插入多个相同的key值当value值不同
}
}
map和set的底层实际都是红黑树,红黑树又是以二叉搜索树为基准。
底层实现
先介绍:二叉搜索树。
二叉搜索树
二叉搜索树的性质就是,完成左子树的节点总是比父节点的值小,右子树总是比父节点大。
二叉搜索树的插入:这个相对较简单,就是找到一个节点,如果节点的值满足比插入值小,且右节点为空,或者比插入值大,左节点为空。
示例代码
#include <bits/stdc++.h>
using namespace std;
template <class T>
struct BSTNode
{
BSTNode(const T &x = T())
:data(x)
,left(nullptr)
,right(nullptr)
{}
T data;
BSTNode<T> *left, *right;
};
template<class T>
class BSTree
{
private:
typedef RBTreeNode<KeyType,ValueType>* RBTreeNodePtr;
RBTreeNodePtr m_root;
typedef BSTNode<T> Node;
Node *root;
public:
BSTree()
:root(nullptr)
{
}
bool insert(const T& data)
{
if(root==nullptr)//单独处理下头结点
{
root = new Node;
root->data = data;
return true;
}
Node *curNode = root;
while(curNode!=nullptr)
{
if(data<curNode->data)
{
if(curNode->left==nullptr)
{
curNode->left = new Node;
curNode->left->data = data;
return true;
}
curNode = curNode->left;
}
else if(data>curNode->data)
{
if(curNode->right==nullptr)
{
curNode->right = new Node;
curNode->right->data = data;
return true;
}
curNode = curNode->right;
}
else
{
//有相同的插入失败。
curNode = nullptr;
break;
}
}
return false;
}
稍微麻烦点的是删除
erase:删除某个节点,通过二叉搜索树先找到这个节点。(find可以自己去实现比较简单,逻辑和insert类似)找到某个节点之后。
分以下几种:
1.删除节点左节点为空,或者右节点为空。
那么,让其右节点或者左节点顶替即可。
右节点为空示意图
2,删除节点左右节点都为空,删除该节点,将其父节点指向置为空即可。
3,若左右节点都不为空,则找到其左边最小,或者右边最小节点来与其交换,然后删除出交换的那个节点位置即可。
**上面就是删除节点的基本思路,虽然思路是那样,但是里面有一个特殊的节点删除值得注意,那就是根节点,根节点是没有父节点,erase时是需要额外注意的。
bool erase(const T&data)
{
Node* parent = root;
Node* curnode = root;
while(curnode)
{
if(curnode->data>data)
{
parent = curnode;
curnode = curnode->left;
}
else if(curnode->data<data)
{
parent = curnode;
curnode = curnode->right;
}
else//开始删除
{
if(curnode->left==nullptr)
{
if(curnode==root)
{
root=curnode->right;
}
else
{
if(parent->left==curnode)
{
parent->left = curnode->right;
}
else
{
parent->right = curnode->right;
}
}
}
else if(curnode->right==nullptr)
{
if(curnode==root)
{
root=curnode->left;
}
else
{
if(parent->left==curnode)
{
parent->left = curnode->left;
}
else
{
parent->right = curnode->left;
}
}
}
else
{
//说明要找左边最大或者右边最小,就必有父节点
//这里找的右边
Node* ChildLeft = curnode->right;
parent = curnode;
while(ChildLeft->left)
{
parent = ChildLeft;
ChildLeft = ChildLeft->left;
}
swap(ChildLeft->data,curnode->data);
//这里判断一次,是为了防止右节点的左子树直接就是空
//这里就需要吧右节点直接顶替,考虑情况,算下左右节点。
if(ChildLeft==parent->left)
{
parent->left = ChildLeft->right;
}
else
{
parent->right = ChildLeft->right;
}
delete ChildLeft;
ChildLeft = nullptr;
}
return 1;
}
}
return 0;
}
红黑树
对二叉搜索树搞明白之后,接下来看红黑树。
满足以下条件,我们称之为红黑树:
1.每个节点要么是红色,要么是黑色。
2.根节点必须是黑色。
3.所有叶子节点(这里叶子结点实际指的就是空节点)都应该是黑色(或者叫都算作黑色)。
4.如果一个节点是红色,则它的两个子节点都是黑色。(红不连续,有说法红黑相见,其实不对,因为有黑-黑的情况)
5.对于每一条从节点到其子孙节点的路径,该路径上的黑色节点数量相同。(任意路径相同的黑色高度)
满足上面的条件,二叉树之间高度差,不会超过两倍,其具体原理就不再介绍了。
红黑树的节点设立如下,为了方便寻找父节点,设立成三叉树,同时设立一个颜色,对于key和val值不重点,整体理解成key值即可。
enum BackgroundColor{
BLACK = 0,RED=1,
};
template <class KeyType,class ValueType>
struct RBTreeNode{
typedef RBTreeNode<KeyType,ValueType>* RBTreeNodePtr;
RBTreeNode(pair<KeyType,ValueType> kv = make_pair(KeyType(),ValueType()),BackgroundColor Inicolor =RED)
: _kv(kv),left(nullptr),right(nullptr),parent(nullptr),color(Inicolor)
{
;
}
pair<KeyType,ValueType> _kv;
RBTreeNodePtr left;
RBTreeNodePtr right;
RBTreeNodePtr parent;
BackgroundColor color;
};
下面是插入的代码,其基本体是和二叉搜索树是一样的,这里由于后面封装的缘故,做了些头结点连接的操作。
因为插入黑节点总是破坏平衡,所以我们插入默认是红,这样即使破坏,也不用破坏路径。
剩下就是调整了。
RBTree中做了些重定义:
typedef RBTreeNode<KeyType,ValueType> * RBTreeNodePtr; 这是为了后序表达更简洁
红黑树的插入
bool insert(const pair<KeyType,ValueType>& kv)
{
if(nullptr==m_root)
{
//让header指向父亲指向根节点,左指向最小,右指向最大
m_root = new RBTreeNode<KeyType,ValueType>(kv,BLACK);
m_header->left = m_root;
m_header->right = m_root;
//根节点父节点是header
m_header->parent = m_root;
m_root->parent = m_header;
return true;
}
if(kv.first==36)
{
int cc = 100;
}
RBTreeNodePtr cur = m_root;
RBTreeNodePtr CurPrt = nullptr;
while(cur)
{
if(cur->_kv.first > kv.first)
{
if(nullptr==cur->left)
{
cur->left = new RBTreeNode(kv);
cur->left->parent = cur;
adjust(cur->left,cur);
break;
}
else
{
cur = cur->left;
CurPrt = cur;
}
}
else if(cur->_kv.first < kv.first)
{
if(nullptr==cur->right)
{
cur->right = new RBTreeNode(kv);
cur->right->parent = cur;
adjust(cur->right,cur);
break;
}
else
{
cur = cur->right;
CurPrt = cur;
}
}
else
{
//已经存在,暂时先不做处理,认为插入失败
break;
return false;
}
}
m_root->color= BLACK;
m_header->left = LeftestNode();
m_header->right = RightestNode();
return true;
}
插入节点后的调整
首先我们就要考虑什么时候要调整:
1.父亲是黑色:不需要调整,符合规则,直接退出
2.父亲是红色节点:那么就要考虑如何做了,是不是总得对当前节点调整颜色,那么会影响的什么?
调整的话会对哪些有影响:
1.父亲节点,
2.祖父节点
3.舅舅节点
倘若Cur变成黑色,是不是这三个会被影响,可能由于他们之间的关系,导致路径距离不一样,所以我们需要考虑做如下调整。
进行分类
一:Unc是红色,进行如下调整即可,交换祖父和Cur的节点即可。
二:Unc是黑色(不论是空还是是黑色,因为空也算黑色)
1.左左,即父亲是爷爷左儿子,儿子是父亲的左儿子, 那我们是不是让父亲作为祖父那个节点,使Cur作为左节点,G作为父亲的右节点即可。
旋转上选择所谓的右旋(被旋转节点对旋转中心而言的右旋也就是顺时针),就会得到下面的结果,且其整个黑色节点高度不会改变。
2.1:剩下就是左右,父节点是爷爷节点的左节点,Cur是父节点的右节点。
这种情况下,先对父亲左旋(逆时针),再对祖父右旋(顺时针即可)。
3.1和3.2分别是右右和右左,这里不过多介绍。其实和上面两种情况是对称的,不多赘述。
实现代码如下:
RBTreeNodePtr RightRotate(RBTreeNodePtr root)//传要传输的旋转的父节点其父亲所指向的那个节点
{
RBTreeNodePtr left = root->left;
RBTreeNodePtr Childright = left->right;
root->left = Childright;
if(Childright)
{
Childright->parent = root;
}
//节点之间的值就算交换完毕
left->right = root;
root->parent = left;
return left;
}
void Rotate(RBTreeNodePtr parent,RBTreeNodePtr(RBTree<KeyType, ValueType>::*Rotatefunc)(RBTreeNodePtr))
{
RBTreeNodePtr PP = parent->parent;
if(PP && PP!=m_header)
{
RBTreeNodePtr Child = (this->*Rotatefunc)(parent);
if(PP->left == parent)
{
PP->left = Child;
Child->parent = PP;
}
else
{
PP->right = Child;
Child->parent = PP;
}
}
else//说明遇见了根节点
{
m_root= (this->*Rotatefunc)(parent);
m_root->parent = m_header;
m_header ->parent = m_root;
}
}
RBTreeNodePtr LeftRotate(RBTreeNodePtr root)
{
RBTreeNodePtr right = root->right;
RBTreeNodePtr Childleft = right->left;
root->right = Childleft;
if(Childleft)
{
Childleft->parent = root;
}
right->left = root;
root->parent = right;
return right;
}
bool adjust(RBTreeNodePtr Cur,RBTreeNodePtr CurPrt)
{
//在节点插入中,Cur一来应该不会是根节点,调整到根节点,直接退出
//应该说,父亲不应该会空,应为根节点会直接插入
RBTreeNodePtr CurGrp = CurPrt->parent;
RBTreeNodePtr CurUnc= nullptr;
while(Cur && Cur!=m_root)//直到不会是根节点
{
if(CurPrt->color==BLACK)
{
//理论上说,color节点new的时候默认是红,这里防止出现意外操作下
Cur->color = RED;
return true;
}
//每次的舅舅节点
if(CurGrp->left==CurPrt)
{
CurUnc = CurGrp->right;
}
else{
CurUnc = CurGrp->left;
}
if(CurUnc&& CurUnc->color==RED)//舅舅节点是红色,向上调整
{
CurPrt->color = BLACK;
CurUnc->color = BLACK;
Cur->color = RED;
//处理祖孙的颜色变化
Cur = CurGrp;
Cur->color = RED;
//调整其父亲,祖父节点,因为每次舅舅节点都会算,就不需要额外调整
CurPrt = Cur->parent;
CurGrp = CurPrt->parent;
}
else//舅舅节点是黑色
{
if(CurPrt==CurGrp->left)
{
if(Cur==CurPrt->left)
{
//左左,对祖父节点进行右单旋
CurGrp->color = RED;
CurPrt->color = BLACK;
Rotate(CurGrp,&RightRotate);
}
else{
//左右,先对父亲左单旋,再对祖父右单旋
//
Cur->color = BLACK;
CurGrp->color = CurPrt->color = RED;
Rotate(CurPrt,&LeftRotate);
Rotate(CurGrp,&RightRotate);
}
}
else if(CurPrt==CurGrp->right)
{
if(Cur==CurPrt->right)
{
//右右
CurGrp->color = BackgroundColor::RED;
CurPrt->color = BLACK;
Rotate(CurGrp,&LeftRotate);
}
else
{
//右左
Cur->color = BLACK;
CurGrp->color = CurPrt->color = RED;
Rotate(CurPrt,&RightRotate);
Rotate(CurGrp,&LeftRotate);
}
}
//不用在进行调整,至此结束
break;
}
}
return false;
}
红黑树的删除:由于目前能力及时间问题未能实现更新,后序会更新出红黑树底层的删除
目前完整的代码:
#pragma once
#include <bits/stdc++.h>
using namespace std;
enum BackgroundColor{
BLACK = 0,RED=1,
};
template <class KeyType,class ValueType>
struct RBTreeNode{
typedef RBTreeNode<KeyType,ValueType>* RBTreeNodePtr;
RBTreeNode(pair<KeyType,ValueType> kv = make_pair(KeyType(),ValueType()),BackgroundColor Inicolor =RED)
: _kv(kv),left(nullptr),right(nullptr),parent(nullptr),color(Inicolor)
{
;
}
pair<KeyType,ValueType> _kv;
RBTreeNodePtr left;
RBTreeNodePtr right;
RBTreeNodePtr parent;
BackgroundColor color;
};
template <class KeyType,class ValueType>
class RBTree{
private:
typedef RBTreeNode<KeyType,ValueType>* RBTreeNodePtr;
RBTreeNodePtr m_root;
RBTreeNodePtr m_header;
private:
RBTreeNodePtr LeftestNode()
{
RBTreeNodePtr cur = m_root;
while(cur && cur->left)
{
cur = cur->left;
}
return cur;
}
RBTreeNodePtr RightestNode()
{
RBTreeNodePtr cur = m_root;
while(cur&&cur->right)
{
cur = cur->right;
}
return cur;
}
RBTreeNodePtr RightRotate(RBTreeNodePtr root)//传要传输的旋转的父节点其父亲所指向的那个节点
{
RBTreeNodePtr left = root->left;
RBTreeNodePtr Childright = left->right;
root->left = Childright;
if(Childright)
{
Childright->parent = root;
}
//节点之间的值就算交换完毕
left->right = root;
root->parent = left;
return left;
}
void Rotate(RBTreeNodePtr parent,RBTreeNodePtr(RBTree<KeyType, ValueType>::*Rotatefunc)(RBTreeNodePtr))
{
RBTreeNodePtr PP = parent->parent;
if(PP && PP!=m_header)
{
RBTreeNodePtr Child = (this->*Rotatefunc)(parent);
if(PP->left == parent)
{
PP->left = Child;
Child->parent = PP;
}
else
{
PP->right = Child;
Child->parent = PP;
}
}
else//说明遇见了根节点
{
m_root= (this->*Rotatefunc)(parent);
m_root->parent = m_header;
m_header ->parent = m_root;
}
}
RBTreeNodePtr LeftRotate(RBTreeNodePtr root)
{
RBTreeNodePtr right = root->right;
RBTreeNodePtr Childleft = right->left;
root->right = Childleft;
if(Childleft)
{
Childleft->parent = root;
}
right->left = root;
root->parent = right;
return right;
}
bool adjust(RBTreeNodePtr Cur,RBTreeNodePtr CurPrt)
{
//在节点插入中,Cur一来应该不会是根节点,调整到根节点,直接退出
//应该说,父亲不应该会空,应为根节点会直接插入
RBTreeNodePtr CurGrp = CurPrt->parent;
RBTreeNodePtr CurUnc= nullptr;
while(Cur && Cur!=m_root)//直到不会是根节点
{
if(CurPrt->color==BLACK)
{
//理论上说,color节点new的时候默认是红,这里防止出现意外操作下
Cur->color = RED;
return true;
}
//每次的舅舅节点
if(CurGrp->left==CurPrt)
{
CurUnc = CurGrp->right;
}
else{
CurUnc = CurGrp->left;
}
if(CurUnc&& CurUnc->color==RED)//舅舅节点是红色,向上调整
{
CurPrt->color = BLACK;
CurUnc->color = BLACK;
Cur->color = RED;
//处理祖孙的颜色变化
Cur = CurGrp;
Cur->color = RED;
//调整其父亲,祖父节点,因为每次舅舅节点都会算,就不需要额外调整
CurPrt = Cur->parent;
CurGrp = CurPrt->parent;
}
else//舅舅节点是黑色
{
if(CurPrt==CurGrp->left)
{
if(Cur==CurPrt->left)
{
//左左,对祖父节点进行右单旋
CurGrp->color = RED;
CurPrt->color = BLACK;
Rotate(CurGrp,&RightRotate);
}
else{
//左右,先对父亲左单旋,再对祖父右单旋
//
Cur->color = BLACK;
CurGrp->color = CurPrt->color = RED;
Rotate(CurPrt,&LeftRotate);
Rotate(CurGrp,&RightRotate);
}
}
else if(CurPrt==CurGrp->right)
{
if(Cur==CurPrt->right)
{
//右右
CurGrp->color = BackgroundColor::RED;
CurPrt->color = BLACK;
Rotate(CurGrp,&LeftRotate);
}
else
{
//右左
Cur->color = BLACK;
CurGrp->color = CurPrt->color = RED;
Rotate(CurPrt,&RightRotate);
Rotate(CurGrp,&LeftRotate);
}
}
//不用在进行调整,至此结束
break;
}
}
return false;
}
public:
void InorderPrint()
{
InorderPrintR(m_root);
cout<<"\n";
}
void InorderPrintR(RBTreeNodePtr root)
{
if(root==nullptr)
{
return ;
}
InorderPrintR(root->left);
cout<<root->_kv.first<<" ,";
InorderPrintR(root->right);
}
RBTree()
: m_root(nullptr)
{
//
m_header = new RBTreeNode(make_pair(KeyType(),ValueType()));
m_header->left = m_header->right = m_header->parent = nullptr;
m_header->color = BLACK;
}
bool insert(const pair<KeyType,ValueType>& kv)
{
if(nullptr==m_root)
{
//让header指向父亲指向根节点,左指向最小,右指向最大
m_root = new RBTreeNode<KeyType,ValueType>(kv,BLACK);
m_header->left = m_root;
m_header->right = m_root;
//根节点父节点是header
m_header->parent = m_root;
m_root->parent = m_header;
return true;
}
if(kv.first==36)
{
int cc = 100;
}
RBTreeNodePtr cur = m_root;
RBTreeNodePtr CurPrt = nullptr;
while(cur)
{
if(cur->_kv.first > kv.first)
{
if(nullptr==cur->left)
{
cur->left = new RBTreeNode(kv);
cur->left->parent = cur;
adjust(cur->left,cur);
break;
}
else
{
cur = cur->left;
CurPrt = cur;
}
}
else if(cur->_kv.first < kv.first)
{
if(nullptr==cur->right)
{
cur->right = new RBTreeNode(kv);
cur->right->parent = cur;
adjust(cur->right,cur);
break;
}
else
{
cur = cur->right;
CurPrt = cur;
}
}
else
{
//已经存在,暂时先不做处理,认为插入失败
break;
return false;
}
}
m_root->color= BLACK;
m_header->left = LeftestNode();
m_header->right = RightestNode();
return true;
}
int height(RBTreeNodePtr root)
{
if(root==nullptr)
{
return 0;
}
int leftheight = height(root->left);
int rightheight = height(root->right);
return 1+(leftheight>rightheight?leftheight:rightheight);
}
vector<vector<pair<pair<KeyType,ValueType>,BackgroundColor>>> LevelPrint()
{
const char* COLOR[2] = {"BLACK","RED"};
cout<<"********************************\n\n";
vector<vector<pair<pair<KeyType,ValueType>,BackgroundColor>>> res;
list<RBTreeNodePtr> nodelist(1,m_root);
int NowNodeNum = 1,nextLevelNodeNum = 0;
vector<pair<pair<KeyType,ValueType>,BackgroundColor>> nowlevel;
while(nodelist.size())
{
RBTreeNodePtr p = nodelist.front();
nodelist.pop_front();
nowlevel.push_back(make_pair(p->_kv,p->color));
if(p->left)
{
nodelist.push_back(p->left);
nextLevelNodeNum++;
}
if(p->right)
{
nodelist.push_back(p->right);
nextLevelNodeNum++;
}
if(--NowNodeNum==0)
{
res.push_back(nowlevel);
nowlevel.clear();
NowNodeNum = nextLevelNodeNum;
nextLevelNodeNum = 0;
}
}
for (int i = 0; i < res.size(); i++)
{
for (int j = 0; j < res[i].size(); j++)
{
cout << res[i][j].first.first << " " <<COLOR[res[i][j].second]<<"\t";
}
cout<<endl;
}
cout<<"********************************\n\n";
return res;
}
bool test()
{
RBTreeNodePtr Cur = m_root;
int count = 1;
while(Cur)
{
if(Cur->color==BLACK)
{
count++;
}
Cur = Cur->left;
}
return Judge(m_root,0,count);
}
bool Judge(RBTreeNodePtr root,size_t k,size_t count)
{
if(root==nullptr)
{
return k+1==count;
}
if(root->color==BLACK)
{
k++;
}
return Judge(root->left,k,count)&&Judge(root->right,k,count);
}
};