目录
前言:map和set容器是以平衡二叉搜索树(红黑树)为底层来实现的,与接下来要学习的unordered_map和unordered_set是C++使用最多的关联式容器。
map和set的底层是红黑树,要想学map和set的模拟实现,就要先学红黑树,而学习红黑树前建议先学AVLTree。
一.关联式容器
1.关联式容器
之前学过的vector、list、deque等容器都叫做序列式容器,因为其底层为线性序列的数据结构,里面存储的是元素本身。
而今天所学习的关联式容器也是用来存储数据的,与序列式容器不同的是,其里面存储的是<key, value>结构的键值对,在数据检索时比序列式容器效率更高。
2.树形结构的关联式容器
根据应用场景的不同,STL实现了两种不同结构的关联式容器:树型结构和哈希结构。树型结构的关联式容器主要有四种:map、set、multimap、multiset。这四种容器的共同点是:使用平衡搜索树(红黑树)作为其底层结构,容器中的元素是一个有序的序列。
二.键值对
键值对是用来表示具有一一对应关系的一种结构 ,该结构中一般只包括两个成员变量key和value,key代表键值, value表示与key对应的信息。
三.set
1.介绍
① set是按照一定次序存储元素的容器
② 在set中,元素的value也表示key(value就是key,类型为T),并且每个value(key)必须是唯一的
③ 在内部,set中的元素总是按照其内部比较对象(类型比较)所指示的特定严格弱排序准则进行排序
④ set容器通过key访问单个元素的速度通常比unordered_set容器慢,但它们允许根据顺序对子集进行直接迭代
⑤ set的底层是用平衡搜索二叉树(红黑树)实现的
注意:
① set/multiset与map/multimap不同,map中存储的是真正的键值对<key, value>,set中只放value,但在底层实际存放的是由<value, value>构成的键值对
② set中插入元素时,只需要插入value即可,不需要构造键值对
③ set中的元素不可以重复(因此可以使用set进行去重)
④ 使用set的迭代器遍历set中的元素,可以得到有序序列
⑤ set中的元素默认按照小于来比较(升序)
⑥ set中查找某个元素时,时间复杂度为:O(log2n)
⑦ set中的元素不允许修改
2.set的使用
1.set的模板参数列表
T: set中存放元素的类型,实际在底层存储<value, value>键值对
Compare:set中元素默认按照小于来比较
Alloc:set中元素空间的管理方式,使用STL提供的空间配置器管理
2.构造
set() 构造空的set
set(Inputlterator first, Inputlterator last) 用(first, last)区间中的元素构造set
set(const set<Key>) set的拷贝构造
3.迭代器
迭代器与之前相同,依旧是正向、反向、const修饰的迭代器
// 排序 + 去重
set<int>::iterator it = s.begin();
while (it != s.end())
{
//*it = 10;
cout << *it << " ";
++it;
}
cout << endl;
for (auto e : s)
{
cout << e << " ";
}
cout << endl;
4.容量操作
empty() 检测set是否为空,空返回true,否则返回false
size() 返回set中有效元素的个数
5.增删查操作
pair<iterator, bool> insert(const value_type& x) 插入(在set中插入元素x,实际插 入的是<x, x>构成的键值对,如果 插入成功,返回<该元素在set中的 位置, true>,如果插入失败,说明 x在set中已经存在,返回<x在set 中的位置, false>)
void erase(iterator position) 删除set中position位置上的元素
size_type erase(const key_type& x) (multiset)删除set中值为x的元素,返回删除的 元素的个数
void erase(iterator first, iterator last) 删除set中(first, last)区间中的元素
void swap(set<Key, Compare, Allocator>& st) 交换set中的元素
void clear() 将set中的元素清空
iterator find(const key_type& x) 返回set中值为x的元素的位置
size_type count(const key_type& x) 返回set中值为x的元素的个数
iterator lower_bound(const value_type& val) 返回>=val的位置的迭代器
upper_bound(const value_type& val) 返回>val的位置的迭代器
void test_set1()
{
set<int> s;
s.insert(4);
s.insert(5);
s.insert(2);
s.insert(1);
s.insert(1);
s.insert(3);
s.insert(2);
s.insert(1);
cout << s.erase(3) << endl;
cout << s.erase(30) << endl;
for (auto e : s)
{
cout << e << " ";
}
cout << endl;
set<int>::iterator pos = s.find(3);
if (pos != s.end())
s.erase(pos);
for (auto e : s)
{
cout << e << " ";
}
cout << endl;
if (s.count(5))
{
cout << "5在" << endl;
}
}
void test_set2()
{
set<int> s;
s.insert(4);
s.insert(5);
s.insert(1);
s.insert(3);
s.insert(2);
s.insert(7);
s.insert(9);
for (auto e : s)
{
cout << e << " ";
}
cout << endl;
// 返回>x位置的迭代器 -》 都是返回 7位置的迭代器
//set<int>::iterator upIt = s.upper_bound(5); // 存在
//upIt = s.upper_bound(6); // 不存在
// 删除x <= <= y的区间 删除 [x,y]
int x, y;
cin >> x >> y;
auto leftIt = s.lower_bound(x); // [
auto rightIt = s.upper_bound(y); // )
s.erase(leftIt, rightIt);
for (auto e : s)
{
cout << e << " ";
}
cout << endl;
}
四.map
1.介绍
① map是关联式容器,它按照特定的次序(按照key来比较)存储由键值key和值value组合而成的元素
② 在map中,键值key通常用于排序和唯一的标识元素,而值value中存储与此键值key关联的内容,键值key和值value的类型可能不同,并且在map的内部,key与value通过成员类型value_type绑定在一起,与其取别名为pair
③ 在内部,map中的元素总是按照键值key进行比较排序的
④ map中通过键值访问单个元素的速度通常比unordered_map容器慢,但map允许根据顺序对元素进行直接迭代(即对map中的元素进行迭代时,可以得到一个有序的序列)
⑤ map支持下标访问符,即在[]中放入key,就可以找到与key对应的value
⑥ map的底层是用平衡搜索二叉树(红黑树)实现的
2.map的使用
1.map的模板参数说明
key:键值对中key的类型
T:键值对
Compare:比较器的类型,map中的元素是按照key来比较的,缺省情况下按照小于来比较,一般情况下(内置类型元素)该参数不需要传递,如果无法比较时(自定义类型),需要用户自己显式传递比较规则(一般情况下按照函数指针或者仿函数来传递)
Alloc:通过空间配置器来申请底层空间,不需要用户传递,除非用户不想使用标准库提供的空间配置器
2.构造
map() 构造一个空的map
3.迭代器
迭代器与之前相同,依旧是正向、反向、const修饰的迭代器
// 遍历
//map<string, string>::iterator it = dict.begin();
auto it = dict.begin();
while (it != dict.end())
{
//cout << *it << " "; // it->operator*()
//cout << (*it).first << ":" << (*it).second << endl;
cout << it->first << ":" << it->second << endl;
++it;
}
cout << endl;
for (const auto& kv : dict)
{
cout << kv.first << ":" << kv.second << endl;
}
4.容量操作与元素访问
empty() 检查map中的元素是否为空
size() 返回map中有效元素的个数
mapped_type& operator[](const key_type& k) 返回key对应的value
5.增删查改操作
pair<iterator, bool> insert(const value_type& x) 在map中插入键值对x,注意x是一 个键值对,返回值也是键值对: iterator代表新插入元素的位置, bool代表释放插入成功
void erase(iterator position) 删除position位置上的元素
size_type erase(const key_type& x) 删除键值为x的元素
void erase(iterator first) 删除(first, last)区间中的元素
void swap(map<Key, T, Compare, Allocater>& mp) 交换两个map中的元素
void clear() 将map中的元素清空
iterator find(const key_type& x) 在map中插入key为x的元素,找到返回该元素的位置 的迭代器,否则返回end
const_iterator find(const key_type& x) 在map中插入key为x的元素,找到返回该元素 的位置的const迭代器,否则返回cend
size_type count(const key_type& x) 返回key为x的键值在map中的个数,注意map中 key是唯一的,因此该函数的返回值要么为0,要 么为1,因此也可以用该函数来检测一个key是否 在map中
void test_map1()
{
map<string, string> dict;
// pair构造函数
dict.insert(pair<string, string>("sort", "排序"));
pair<string, string> kv("insert", "插入");
dict.insert(kv);
// make_pair
auto ret1 = dict.insert(make_pair("left", "左边"));
auto ret2 = dict.insert(make_pair("left", "剩余"));
dict["operator"] = "重载"; // 插入+修改
dict["left"] = "左边、剩余"; // 修改
dict["erase"]; // 插入
cout << dict["left"] << endl; // 查找
// C++11方法
//dict.insert({ "right", "右边" });
// 遍历
//map<string, string>::iterator it = dict.begin();
auto it = dict.begin();
while (it != dict.end())
{
//cout << *it << " "; // it->operator*()
//cout << (*it).first << ":" << (*it).second << endl;
cout << it->first << ":" << it->second << endl;
++it;
}
cout << endl;
for (const auto& kv : dict)
{
cout << kv.first << ":" << kv.second << endl;
}
}
void test_map2()
{
string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };
// 方法1
/*map<string, int> countMap;
for (auto& str : arr)
{
map<string, int>::iterator it = countMap.find(str);
if (it != countMap.end())
{
it->second++;
}
else
{
countMap.insert(make_pair(str, 1));
}
}*/
// 方法2
//map<string, int> countMap;
//for (auto& str : arr)
//{
// //pair<map<string, int>::iterator, bool> ret = countMap.insert(make_pair(str, 1));
// auto ret = countMap.insert(make_pair(str, 1));
// if (ret.second == false)
// {
// ret.first->second++;
// }
//}
// 方法3
map<string, int> countMap;
for (auto& str : arr)
{
countMap[str]++;
}
for (const auto& kv : countMap)
{
cout << kv.first << ":" << kv.second << endl;
}
}
五.multiset和multimap
1.multiset介绍
① multiset是按照特定顺序存储元素的容器,其中元素是可以重复的
② 在multiset中,元素的value也会识别它(因为multiset中本身存储的就是<value, value>组成的键值对,因此value本身就是key,key就是value,类型为T),multiset元素的值不能在容器中进行修改(因为元素总是const的),但可以从容器中插入或删除
③ 在内部,multiset中的元素总是按照其内部比较规则(类型比较)所指示的特定严格弱排序准则进行排序
④ multiset容器通过key访问单个元素的速度通常比unordered_multiset容器慢,但当使用迭代器遍历时会得到一个有序序列
⑤ multiset底层结构为二叉搜索树(红黑树)
注意:
① multiset中在底层中存储的是<value, value>的键值对
② multiset的插入接口中只需要插入即可
③ 与set的区别是,multiset中的元素可以重复,set中的元素不能重复
④ 使用迭代器对multiset中的元素进行遍历,可以得到有序的序列
⑤ multiset中的元素不能修改
⑥ 在multiset中找某个元素,时间复杂度为O(log2n)
⑦ multiset的作用:可以对元素进行排序
2.multimap介绍
① multimap是关联式容器,它按照特定的顺序,存储由key和value映射的键值对<key, value>,其中多个键值对直接的key是可以重复的
② 在multimap中,通常按照key排序和唯一的标识元素,而映射的value存储与key关联的内容。key和value的类型可能不同,通过multimap内部的成员类型value_type组合在一起,value_type是组合key和value的键值对
③ 在内部,multimap中的元素总是通过其内部比较对象,按照指定的特定严格弱排序标准对key进行排序的
④ multimap通过key访问单个元素的速度通常比unordered_multimap容器慢,但是使用迭代器直接遍历multimap中的元素可以得到关于key有序的序列
⑤ multimap的底层结构为二叉搜索树(红黑树)
注意:
① multimap中的key是可以重复的
② multimap中的元素默认将key按照小于来比较
③ multimap中没有重载operator[]操作
④ 使用时与map包含的头文件相同
multiset和set的使用几乎相同,multimap和map的使用几乎相同(multimap不能用operator[])
六.红黑树改造
map和set的模拟实现实际上就是在红黑树的基础上进行封装,因此主要实现的是红黑树,红黑树实现好了,map和set只要封装一下就可以了。
1.节点内部
因为我们不知道要用红黑树来实现set还是map,所以我们模板参数就用一个T,并且数据用_data(而不是kv或key)。
template<class T>
struct RBTreeNode
{
RBTreeNode<T>* _left;
RBTreeNode<T>* _right;
RBTreeNode<T>* _parent;
T _data;
Color _col;
RBTreeNode(const T& data)
: _data(data)
, _left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _col(RED)
{}
};
2.增加仿函数
template<class K, class T, class KeyOfT>
增加KeyOfT的仿函数(支持取出T对象中key的仿函数)
set RBTree<K, K>
map RBTree<K, pair<K, V>>
如果是set则比较好取出key进行比较,而如果是map就需要先取出kv再找到first才能进行比较,因此我们需要实现一个仿函数来进行封装。
这里的插入函数就要通过创建KeyOfT类型的对象,通过仿函数来完成对于不同的T对象实现相同的操作。
pair<iterator, bool> Insert(const T& data)
{
// 1.搜索树的规则插入
// 2.看是否违反平衡规则,如果违反就需要处理:旋转
if (_root == nullptr)
{
_root = new Node(data);
_root->_col = BLACK;
return make_pair(iterator(_root), true);
}
KeyOfT kot;
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (kot(cur->_data) < kot(data))
{
parent = cur;
cur = cur->_right;
}
else if (kot(cur->_data) > kot(data))
{
parent = cur;
cur = cur->_left;
}
else
{
return make_pair(iterator(cur), true);
}
}
cur = new Node(data);
Node* newnode = cur;
cur->_col = RED;
if (kot(parent->_data) < kot(data))
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
cur->_parent = parent;
// 存在连续红色节点
while (parent && parent->_col == RED)
{
Node* grandfather = parent->_parent;
assert(grandfather);
if (grandfather->_left == parent)
{
Node* uncle = grandfather->_right;
// 情况一:叔叔存在且为红
if (uncle && uncle->_col == RED)
{
// 变色
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
// 继续往上处理
cur = grandfather;
parent = cur->_parent;
}
// 叔叔不存在 or 叔叔存在且为黑
else
{
// 情况二:单旋(右单旋)
if (cur == parent->_left)
{
// g
// p
// c
RotateR(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
}
// 情况三:双旋(左右双旋)
else
{
// g
// p
// c
RotateL(parent);
RotateR(grandfather);
cur->_col = BLACK;
grandfather->_col = RED;
}
break;
}
}
// grandfather->_right == parent
else
{
Node* uncle = grandfather->_left;
// 情况一:叔叔存在且为红
if (uncle && uncle->_col == RED)
{
// 变色
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
// 继续往上处理
cur = grandfather;
parent = cur->_parent;
}
// 叔叔不存在 or 叔叔存在且为黑
else
{
// 情况二:单旋(左单旋)
if (cur == parent->_right)
{
// g
// p
// c
RotateL(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
}
// 情况三:双旋(右左双旋)
else
{
// g
// p
// c
RotateR(parent);
RotateL(grandfather);
cur->_col = BLACK;
grandfather->_col = RED;
}
break;
}
}
}
_root->_col = BLACK;
return make_pair(iterator(newnode), true);
}
3.增加迭代器
template<class T, class Ref, class Ptr>
struct __RBTreeIterator
{
typedef RBTreeNode<T> Node;
typedef __RBTreeIterator<T, Ref, Ptr> Self;
Node* _node;
__RBTreeIterator(Node* node)
: _node(node)
{}
Ref operator*()
{
return _node->_data;
}
Ptr operator->()
{
return &_node->_data;
}
Self& operator++()
{
if (_node->_right == nullptr)
{
// 找祖先里面,孩子是父亲的那个
Node* cur = _node;
Node* parent = cur->_parent;
while (parent && parent->_right == cur)
{
cur = cur->_parent;
parent = parent->_parent;
}
_node = parent;
}
else
{
// 右子树的最左节点
Node* subLeft = _node->_right;
while (subLeft->_left)
{
subLeft = subLeft->_left;
}
_node = subLeft;
}
return *this;
}
Self operator++(int)
{
Self tmp(*this);
++(*this);
return tmp;
}
Self& operator--()
{
if (_node->_left == nullptr)
{
// 找祖先里面,孩子是父亲
Node* cur = _node;
Node* parent = cur->_parent;
while (parent && cur == parent->_left)
{
cur = cur->_parent;
parent = parent->_parent;
}
_node = parent;
}
else
{
// 左子树的最右节点
Node* subRight = _node->_left;
while (subRight->_right)
{
subRight = subRight->_right;
}
_node = subRight;
}
return *this;
}
Self operator--(int)
{
Self tmp(*this);
--(*this);
return tmp;
}
bool operator!=(const Self& s) const
{
return _node != s._node;
}
bool operator==(const Self& s) const
{
return _node == s->_node;
}
};
这个迭代器的增加类似于链表list类的实现C++ list类(包括反向迭代器适配器的实现)_糖果雨滴a的博客-CSDN博客_list 反向迭代器
需要我们自己去封装一个迭代器,这里的模板参数中Ref是T&,Ptr是T*,然后将节点类typedef为Node,将自己typedef为Self。
接下来就是分别实现各种操作符重载,operator*,->,!=,==都比较简单,这里不过多赘述。而operator++要详细的说一下。
我们根据这个图来说明:
我们实现的++是中序遍历,左子树 根 右子树。这里因为是3叉链,因此我们可以有比之前更简单的代码实现。这里我们实现迭代版的。
这里我们可以根据当前位置的右子树是否为空来进行分情况讨论:
第一种情况:右子树为空-》找孩子是祖先的左的那个节点
第二种情况:右孩子不为空-》找右子树最左的那个节点
根据上面的图来说,第一个it是5所在的迭代器,它的右子树为空,因此找它的祖先里面,孩子是父亲的左的那个,这里6是5的祖先,5是6的左,因此下一个到6的迭代器。6的右子树不为空,找到它右子树的最左节点,7的迭代器。7的右子树为空,因此往上找,6是7的祖先,但是7不是6的左节点,继续往上,8是6和7的祖先,并且7是8的左节点,因此下一个是8的迭代器。右边同理。
代码实现:
Self& operator++()
{
if (_node->_right == nullptr)
{
// 找祖先里面,孩子是父亲的那个
Node* cur = _node;
Node* parent = cur->_parent;
while (parent && parent->_right == cur)
{
cur = cur->_parent;
parent = parent->_parent;
}
_node = parent;
}
else
{
// 右子树的最左节点
Node* subLeft = _node->_right;
while (subLeft->_left)
{
subLeft = subLeft->_left;
}
_node = subLeft;
}
return *this;
}
operator--的实现正好与++相反:
--相当于:右子树 根 左子树
第一种情况:左子树为空-》找孩子是祖先的右的那个节点
第二种情况:左孩子不为空-》找左子树最右的那个节点
代码实现:
Self& operator--()
{
if (_node->_left == nullptr)
{
// 找祖先里面,孩子是父亲
Node* cur = _node;
Node* parent = cur->_parent;
while (parent && cur == parent->_left)
{
cur = cur->_parent;
parent = parent->_parent;
}
_node = parent;
}
else
{
// 左子树的最右节点
Node* subRight = _node->_left;
while (subRight->_right)
{
subRight = subRight->_right;
}
_node = subRight;
}
return *this;
}
这里实现的++和--都是前置的,而后置只需要调用前置的并进行一定修改即可:
Self operator++(int)
{
Self tmp(*this);
++(*this);
return tmp;
}
Self operator--(int)
{
Self tmp(*this);
--(*this);
return tmp;
}
七.set模拟实现(封装改造红黑树)
通过对改造后的红黑树进行封装即可。
注意这里实现的仿函数,直接返回key。(这里因为map,所以才要实现仿函数)
typedef后面加typename的原因是typename关键字在模板声明或定义中有一个重要的用途,那就是声明一个依赖的限定名是一个类型。当我们在模板中使用typedef来定义新的类型别名时,如果这个别名是·依赖于模板参数的类型,那么我们需要使用typename来明确这个别名代表的是一个类型,而不是一个值。
如果没有使用typename,那么编译器可能会将该模板误解为一个静态成员。因此在模板中使用typedef定义新的类型别名,并且这个别名依赖于模板参数时,需要在别名前面加上typename来明确这个别名代表的是一个类型。
namespace hb
{
template<class K>
class set
{
struct SetKeyOfT
{
const K& operator()(const K& key)
{
return key;
}
};
public:
typedef typename RBTree<K, K, SetKeyOfT>::const_iterator iterator;
typedef typename RBTree<K, K, SetKeyOfT>::const_iterator const_iterator;
iterator begin() const
{
return _t.Begin();
}
iterator end() const
{
return _t.End();
}
pair<iterator, bool> insert(const K& key)
{
// pair<typename RBTree<K, K, SetKeyOfT>::iterator, bool> ret = _t.Insert(key);
auto ret = _t.Insert(key);
return pair<iterator, bool>(iterator(ret.first._node), ret.second);
}
iterator find(const K& key)
{
return _t.Find(key);
}
private:
RBTree<K, K, SetKeyOfT> _t;
};
}
八.map模拟实现(封装改造红黑树)
这里面仿函数返回的是kv.first。
map比set多的还有一个operator[],因为这个operator[],就导致红黑树内的insert函数需要返回pair,这样实现operator[]更简单。
namespace hb
{
template<class K, class V>
class map
{
struct MapKeyOfT
{
const K& operator()(const pair<K, V>& kv)
{
return kv.first;
}
};
public:
typedef typename RBTree<K, pair<K, V>, MapKeyOfT>::iterator iterator;
typedef typename RBTree<K, pair<K, V>, MapKeyOfT>::const_iterator const_iterator;
iterator begin()
{
return _t.Begin();
}
iterator end()
{
return _t.End();
}
pair<iterator, bool> insert(const pair<K, V>& kv)
{
return _t.Insert(kv);
}
iterator find(const K& key)
{
return _t.Find(key);
}
V& operator[](const K& key)
{
pair<iterator, bool> ret = insert(make_pair(key, V()));
return ret.first->second;
}
private:
RBTree<K, pair<K, V>, MapKeyOfT> _t;
};
}
九.模拟实现总代码
1.RBTree.h
#pragma once
#include <assert.h>
enum Color
{
RED,
BLACK,
};
template<class T>
struct RBTreeNode
{
RBTreeNode<T>* _left;
RBTreeNode<T>* _right;
RBTreeNode<T>* _parent;
T _data;
Color _col;
RBTreeNode(const T& data)
: _data(data)
, _left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _col(RED)
{}
};
template<class T, class Ref, class Ptr>
struct __RBTreeIterator
{
typedef RBTreeNode<T> Node;
typedef __RBTreeIterator<T, Ref, Ptr> Self;
Node* _node;
__RBTreeIterator(Node* node)
: _node(node)
{}
Ref operator*()
{
return _node->_data;
}
Ptr operator->()
{
return &_node->_data;
}
Self& operator++()
{
if (_node->_right == nullptr)
{
// 找祖先里面,孩子是父亲的那个
Node* cur = _node;
Node* parent = cur->_parent;
while (parent && parent->_right == cur)
{
cur = cur->_parent;
parent = parent->_parent;
}
_node = parent;
}
else
{
// 右子树的最左节点
Node* subLeft = _node->_right;
while (subLeft->_left)
{
subLeft = subLeft->_left;
}
_node = subLeft;
}
return *this;
}
Self operator++(int)
{
Self tmp(*this);
++(*this);
return tmp;
}
Self& operator--()
{
if (_node->_left == nullptr)
{
// 找祖先里面,孩子是父亲
Node* cur = _node;
Node* parent = cur->_parent;
while (parent && cur == parent->_left)
{
cur = cur->_parent;
parent = parent->_parent;
}
_node = parent;
}
else
{
// 左子树的最右节点
Node* subRight = _node->_left;
while (subRight->_right)
{
subRight = subRight->_right;
}
_node = subRight;
}
return *this;
}
Self operator--(int)
{
Self tmp(*this);
--(*this);
return tmp;
}
bool operator!=(const Self& s) const
{
return _node != s._node;
}
bool operator==(const Self& s) const
{
return _node == s->_node;
}
};
// T决定红黑树存什么数据
// set RBTree<K, K>
// map RBTree<K, pair<K, V>>
// KeyOfT -> 支持取出T对象中key的仿函数
template<class K, class T, class KeyOfT>
class RBTree
{
typedef RBTreeNode<T> Node;
public:
typedef __RBTreeIterator<T, T&, T*> iterator;
typedef __RBTreeIterator<T, const T&, const T*> const_iterator;
iterator Begin()
{
Node* subLeft = _root;
while (subLeft && subLeft->_left)
{
subLeft = subLeft->_left;
}
return iterator(subLeft);
}
iterator End()
{
return iterator(nullptr);
}
const_iterator Begin() const
{
Node* subLeft = _root;
while (subLeft && subLeft->_left)
{
subLeft = subLeft->_left;
}
return const_iterator(subLeft);
}
const_iterator End() const
{
return const_iterator(nullptr);
}
pair<iterator, bool> Insert(const T& data)
{
// 1.搜索树的规则插入
// 2.看是否违反平衡规则,如果违反就需要处理:旋转
if (_root == nullptr)
{
_root = new Node(data);
_root->_col = BLACK;
return make_pair(iterator(_root), true);
}
KeyOfT kot;
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (kot(cur->_data) < kot(data))
{
parent = cur;
cur = cur->_right;
}
else if (kot(cur->_data) > kot(data))
{
parent = cur;
cur = cur->_left;
}
else
{
return make_pair(iterator(cur), true);
}
}
cur = new Node(data);
Node* newnode = cur;
cur->_col = RED;
if (kot(parent->_data) < kot(data))
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
cur->_parent = parent;
// 存在连续红色节点
while (parent && parent->_col == RED)
{
Node* grandfather = parent->_parent;
assert(grandfather);
if (grandfather->_left == parent)
{
Node* uncle = grandfather->_right;
// 情况一:叔叔存在且为红
if (uncle && uncle->_col == RED)
{
// 变色
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
// 继续往上处理
cur = grandfather;
parent = cur->_parent;
}
// 叔叔不存在 or 叔叔存在且为黑
else
{
// 情况二:单旋(右单旋)
if (cur == parent->_left)
{
// g
// p
// c
RotateR(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
}
// 情况三:双旋(左右双旋)
else
{
// g
// p
// c
RotateL(parent);
RotateR(grandfather);
cur->_col = BLACK;
grandfather->_col = RED;
}
break;
}
}
// grandfather->_right == parent
else
{
Node* uncle = grandfather->_left;
// 情况一:叔叔存在且为红
if (uncle && uncle->_col == RED)
{
// 变色
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
// 继续往上处理
cur = grandfather;
parent = cur->_parent;
}
// 叔叔不存在 or 叔叔存在且为黑
else
{
// 情况二:单旋(左单旋)
if (cur == parent->_right)
{
// g
// p
// c
RotateL(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
}
// 情况三:双旋(右左双旋)
else
{
// g
// p
// c
RotateR(parent);
RotateL(grandfather);
cur->_col = BLACK;
grandfather->_col = RED;
}
break;
}
}
}
_root->_col = BLACK;
return make_pair(iterator(newnode), true);
}
private:
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
if (subRL)
subRL->_parent = parent;
Node* ppNode = parent->_parent;
subR->_left = parent;
parent->_parent = subR;
if (parent == _root)
{
_root = subR;
_root->_parent = nullptr;
}
else
{
if (parent == ppNode->_left)
{
ppNode->_left = subR;
}
else
{
ppNode->_right = subR;
}
subR->_parent = ppNode;
}
}
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
if (subLR)
subLR->_parent = parent;
Node* ppNode = parent->_parent;
subL->_right = parent;
parent->_parent = subL;
if (parent == _root)
{
_root = subL;
_root->_parent = nullptr;
}
else
{
if (ppNode->_left == parent)
{
ppNode->_left = subL;
}
else
{
ppNode->_right = subL;
}
subL->_parent = ppNode;
}
}
iterator Find(const K& key)
{
Node* cur = _root;
KeyOfT kot;
while (cur)
{
if (kot(cur->_data) < key)
{
cur = cur->_right;
}
else if (kot(cur->_data) > key)
{
cur = cur->_left;
}
else
{
return iterator(cur);
}
}
return End();
}
private:
Node* _root = nullptr;
};
2.Set.h
#pragma once
#include "RBTree.h"
namespace hb
{
template<class K>
class set
{
struct SetKeyOfT
{
const K& operator()(const K& key)
{
return key;
}
};
public:
typedef typename RBTree<K, K, SetKeyOfT>::const_iterator iterator;
typedef typename RBTree<K, K, SetKeyOfT>::const_iterator const_iterator;
iterator begin() const
{
return _t.Begin();
}
iterator end() const
{
return _t.End();
}
pair<iterator, bool> insert(const K& key)
{
// pair<typename RBTree<K, K, SetKeyOfT>::iterator, bool> ret = _t.Insert(key);
auto ret = _t.Insert(key);
return pair<iterator, bool>(iterator(ret.first._node), ret.second);
}
iterator find(const K& key)
{
return _t.Find(key);
}
private:
RBTree<K, K, SetKeyOfT> _t;
};
}
3.Map.h
#pragma once
#include "RBTree.h"
namespace hb
{
template<class K, class V>
class map
{
struct MapKeyOfT
{
const K& operator()(const pair<K, V>& kv)
{
return kv.first;
}
};
public:
typedef typename RBTree<K, pair<K, V>, MapKeyOfT>::iterator iterator;
typedef typename RBTree<K, pair<K, V>, MapKeyOfT>::const_iterator const_iterator;
iterator begin()
{
return _t.Begin();
}
iterator end()
{
return _t.End();
}
pair<iterator, bool> insert(const pair<K, V>& kv)
{
return _t.Insert(kv);
}
iterator find(const K& key)
{
return _t.Find(key);
}
V& operator[](const K& key)
{
pair<iterator, bool> ret = insert(make_pair(key, V()));
return ret.first->second;
}
private:
RBTree<K, pair<K, V>, MapKeyOfT> _t;
};
void test_map1()
{
map<string, int> m;
m.insert(make_pair("111", 1));
m.insert(make_pair("555", 5));
m.insert(make_pair("333", 3));
m.insert(make_pair("222", 2));
map<string, int>::iterator it = m.begin();
while (it != m.end())
{
cout << it->first << ":" << it->second << endl;
++it;
}
cout << endl;
for (auto& kv : m)
{
cout << kv.first << ":" << kv.second << endl;
}
cout << endl;
}
}