1.简介
除了常见的序列式容器之外,我们也经常使用关联式问题来解决一些问题,关联式容器相比较
序列式容器而言,其主要特性就是它可以通过键值对容器内部的元素来进行索引。
2.RB-tree
2.1 简介
在序列式容器中很大一部分都是通过底层使用红黑树来实现的,所谓红黑树首先他是一个二叉搜索树,树上的每一个结点不是红色就是黑色,并且它还需要满足以下性质:(我们将NULL视为黑色的结点)
1.每个结点b不是红色就是黑色。
2.根节点为黑色。
3.如果某一个结点为红色,那么其子节点必定为黑色。
4.任意一个结点到NULL的任何路径上,其黑节点数目必定是相同的。
2.2 红黑树的迭代器
在任意一个容器的设计中,我们的迭代器的作用都是用来访问容器中的元素,因此在设计的过程中,就需要根据容器的类型来设计不同的迭代器,来完成相应的元素访问操作。
在SGI STL的版本中,红黑树的迭代器实现分为两层,它属于双向迭代器,但是不具备随机访问的功能,与list十分相似,RB-tree的迭代器继承基础迭代器,并使用基础迭代器中的函数来完成相应的+±-操作:
//++操作就是寻找比当前结点大的最小的结点
void increment() {
if (node->right != 0) { //如果有右子节点 状况(1)
node = node->right; //就向右走
while (node->left != nullptr) { //然后一直往左子树走到底
node = node->left; //即是解答
}
}
else { //没有右子节点 状况(2)
base_ptr y = node->parent; //找出父节点
while (node == y->right) { //如果现行结点本身就是一个右子节点
node = y; //就一直上溯 直到不为右子节点为止
y = y->parent;
}
if (node->right != y) node = y; //若此时右子节点不等于此时的父节点 状况(3)此时的父节点即为答案 否则此时的node为解答,状况(4)
}
}
/* 注意 以上判断“若此时的右子节点不等于此时的父节点”,是为了应付一种
* 特殊情况:我们欲寻找根结点的下一节点,而恰巧根节点无右子节点。当然
* 以上特殊做法必须配合RB-tree 根结点与特殊之header之间的特殊关系
*/
//--操作就是寻找比当前结点小的最大的数
void decrement() {
if (node->color == _rb_tree_red && node->parent->parent == node) //如果是红结点 且父节点的父节点等于自己
node = node->right; //状况(1)右节点即为解答
//以上情况发生于node为header时,即(node为end()时)
//注意:header之右节点即mpstright,指向整棵树的max结点
else if (node->left != 0) { //如果有左子节点 状况(2)
base_ptr y = node->left; //令y指向左子节点
while (y->right != 0) //当y有右子节点时
y = y->right; //一直往右子节点走到底
node = y; //最后即为答案
}
else {
base_ptr y = node->parent; //既非根节点 亦无左子节点
while (node == y->left) { //状况3找出父节点
node = y; //当现行结点为左子节点
y = y->parent; //一直交替往上走,直到现行结点不为左子结点
}
node = y; //此时父节点即为答案
}
}
2.3 RB-tree的数据结构
在探索一个容器之前,我们会对于其内部的成员数据十分好奇,在SGI STL中RB-tree一共有三个成员数据,分别来表示树的结点数量,一个header(特殊的实现,其左右子节点分别指向最大值和最小值),以及一个函数指针(用于接收传入的比较键值的函数)。
template<class Key, class Value, class KeyValue, class Compare, class Alloc = alloc>
class rb_tree
{
protected:
typedef rb_tree_value_traits<T> value_traits;
typedef void* void_pointer;
typedef _rb_tree_node_base* base_ptr;
typedef _rb_tree_node<Value> rb_tree_node;
typedef simple_alloc<rb_tree_node, Alloc> rb_tree_node_allocator;
typedef _rb_tree_color_type color_type;
public:
typedef Key key_type;
typedef Value value_type;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef value_type& reference;
typedef const value_type const_reference;
typedef rb_tree_node* link_type;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
protected:
//开辟一个结点
link_type get_node() {
return rb_tree_node_allocator::allocate();
}
//释放一个结点
link_type put_node(link_type p) {
rb_tree_node_allocator::deallocate(p);
}
//创建一个带值的结点
link_type create_node(const value_type& x) {
link_type tmp = get_node();
construct(&tmp->value_field, x);
return tmp;
}
//复制一个结点
link_type clone_node(link_type x) {
link_type tmp = create_node(x->value_field);
tmp->color = x->color;
tmp->left = 0;
tmp->right = 0;
return tmp;
}
//释放
void destroy_node(link_type p) {
destroy(&p->value_field);
put_node(p);
}
protected:
size_type node_count;
//一种特殊处理 其左子节点表示最小值 右子节点表示最大值
link_type header;
Compare key_compare;
//用以下三个函数取得header的成员
link_type root() const {
return (link_type)header->parent;
}
link_type leftmost() const {
return (link_type)header->left;
}
link_type rightmost() const {
return (link_type)header->right;
}
//以下取得结点x
static link_type& left(link_type x) {
return (link_type&)(x->left);
}
static link_type& right(link_type x) {
return (link_type&)(x->right);
}
static link_type& parent(link_type x) {
return (link_type&)(x->parent);
}
static reference value(link_type x) {
return x->value_field;
}
static Key& key(link_type x) {
return KeyValue()(value(x));
}
static color_type& color(link_type x) {
return (color_type&)(x->color);
}
//以下也是为了方便取得结点X的成员
static link_type& left(base_ptr x) {
return (link_type&)(x->left);
}
static link_type& right(base_ptr x) {
return (link_type&)(x->right);
}
static link_type& parent(base_ptr x) {
return (link_type&)(x->parent);
}
static reference value(base_ptr x) {
return (link_type)x->value_field;
}
static Key& key(base_ptr x) {
return KeyValue()(value(link_type(x)));
}
static color_type& color(base_ptr x) {
return (color_type&)(link_type(x)->color);
}
//求极大值和极小值
static link_type minimum(link_type x) {
return (link_type)_rb_tree_node_base::minimum(x);
}
static link_type maximum(link_type x) {
return (link_type)_rb_tree_node_base::maximum(x);
}
};
2.4 RB-tree的元素操作
2.4.1 元素的查找操作
在红黑树中,除了常见的find()操作以外,还有lower_bound()、upper_bound()以及equal_range操作来进行查找操作,这几个操作也是后序中的set以及map中会调用的操作,因此代码如下所示:
//*********************lower_bound()**************************
template <class Key, class Value, class KeyOfValue, class Compare, class Alloc>
typename rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::iterator
rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::
lower_bound(const key_type& key)
{
auto y = header;
auto x = root();
while (x != nullptr)
{
if (!key_comp(value_traits::get_key(x->get_node_ptr()->value), key))
{ // x的value与key比较 如果x大于等于key的话就往左走,否则就往右边走
y = x, x = x->left;
}
else
{
x = x->right;
}
}
return iterator(y);
}
//**********************upper_bound()****************************
template <class Key, class Value, class KeyOfValue, class Compare, class Alloc>
typename rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::iterator
rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::
upper_bound(const key_type& key)
{
auto y = header;
auto x = root();
while (x != nullptr)
{
if (key_comp(key, value_traits::get_key(x->get_node_ptr()->value)))
{ // key < x 于上述刚好相反
y = x, x = x->left;
}
else
{
x = x->right;
}
}
return iterator(y);
}
//*********************equal_range()****************************
template <class Key, class Value, class KeyOfValue, class Compare, class Alloc>
ministl::pair<iterator, iterator>
rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::equal_range(const key_type& key) {
return ministl::pair<iterator, iterator>(lower_bound(key), upper_bound(key));
}
2.4.2 元素的插入操作
在红黑树的实现中,一共有两种不同的插入方式:insert_unique()和insert_equal()操作,前者表示被插入结点的键值在整棵树中必须独一无二,后者表示被插入的键值在整棵树中可以重复。
//***************************insert_equal()*******************************
template <class Key, class Value, class KeyOfValue, class Compare, class Alloc>
typename rb_tree<Key,Value,KeyOfValue,Compare,Alloc>::iterator
rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::insert_equal(const value_type& v) {
link_type y = header;
link_type x = root();
while (x != 0) {
y = x;
x = key_compare(KeyOfValue()(v), key(x)) ? left(x) : right(x);
//以上,遇大则往左边,遇小或者等于则往右
//注:这里的大小比较是v与x进行比较,如果v大于x的话,那么v遇大就往左,否则就往右
}
//以x为新值插入点,y为插入点的父节点,v为新值
return _insert(x, y, v);
}
//***************************insert_unique()*******************************
template <class Key, class Value, class KeyOfValue, class Compare, class Alloc>
pair<typename rb_tree<Key,Value,KeyOfValue,Compare,Alloc>::iterator, bool>
rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::insert_unique(const value_type& v) {
link_type y = header;
link_type x - root();
bool comp = true;
while (x != 0)
{
y = x;
comp = key_compare(KeyOfValue()(v), key(x));
x = comp ? left(x) : right(x);
}
//同样的遇到大的往左 遇到小的往右
iterator j = iterator(y);//令迭代器指向插入点的父节点
if (comp) {//如果离开循环时comp为true表示在插入点的左侧
if (j == begin()) {
//如果插入点是最左侧
//x为插入点,y为插入点的父节点,v为新值
return pair<iterator, bool>(_insert(x, y, v), true);
}
else {
--j;
}
}
//小于新值 表示遇到小 将插于右侧
if (key_compare(key(j->node), KeyOfValue()(v)) {
return pair<iterator, bool>(_insert(x, y, v), true);
}
return pair<iterator, bool>(j, false);
}
其中,真正执行插入操作的是函数_insert()操作:
template<class Key, class Value, class KeyOfValue, class Compare, class Alloc>
typename rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::
iterator rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::
_insert(base_ptr x_, base_ptr y_, const value_type& v) {
//x新值插入点 y是插入点的父节点 v是新值
link_type x = (link_type)x_;
link_type y = (link_type)y_;
link_type z;
//是键值比较大小准则
if (y == header || x != 0 || key_compare(KeyOfValue()(v), key(y))) {
z = create_node(v);
left(y) = z;//这使得当y即为header()时,leftmost() = z;
if (y == header) {
root() = z;
rightmost() = z;
}
else if (y == leftmost()){ //如果y为最左结点
leftmost() = z;//维护leftmost使它永远指向最左节点
}
}
else {
z = create_node(v);
right(y) = z;
if (y == rightmost()) //同样的维护rightmost节点
rightmost() = z;
}
parent(z) = y;//设定新的父节点
left(z) = 0;//设定新结点的左子节点
right(z) = 0;//设定新结点的右子节点
//调整新加入的节点颜色
_rb_tree_rebalance(z, header->parent);
//增加节点数目
++node_count;
return iterator(z);
}
2.4.3 插入操作后结点元素的变化操作
在红黑树中,每个插入的结点都是默认是红色的(不可以为黑色,因为根据红黑树的规定而言,如果插入的每一个结点都是黑色的话,也是会满足那几个规则,但是在这个时候红黑树的所有的结点都是黑色的了,就变成了一颗普通的二叉搜索树,没有那些特殊的性质了)。
进行插入操作后,当前被插入的结点有几种情况:
①:如果结点的父节点以及叔叔结点都是红色,那么就将父节点以及叔叔结点都变为黑色,然后将爷爷结点的颜色变为红色。
②:如果插入的结点的父节点的颜色是红色,叔叔结点的颜色是黑色,并且当前结点是右子节点,那么久进行一次左旋操作。
③:如果插入结点的父节点的颜色是红色,叔叔结点的颜色是黑色,并且当前结点是左子节点,那么就进行一次右旋操作。
//************************_rb_tree_rebalance()*****************************
inline void _rb_tree_rebalance(_rb_tree_node_base* x, _rb_tree_node_base* &root) {
x->color = _rb_tree_red;
while (x != root && x->parent->color == _rb_tree_red) {
if (x->parent == x->parent->parent->left) {
_rb_tree_node_base* y = x->parent->parent->right;
if (y && y->color == _rb_tree_red) {
x->parent->color == _rb_tree_black;
y->color = _rb_tree_black;
x->parent->parent->color = _rb_tree_red;
x = x->parent->parent;
}
else {
if (x == x->parent->right) {
x = x->parent;
_rb_tree_rotate_left(x, root);//左旋
}
//与左旋相比,右旋稍微麻烦一些,就是要将其父节点变为黑色,将爷爷节点变为红色
x->parent->color = _rb_tree_black;
x->parent->parent->color = _rb_tree_red;
_rb_tree_rotate_right(x->parent->parent, root);//右旋
}
}
else {
_rb_tree_node_base* y = x->parent->parent->left;
if (y && y->color == _rb_tree_red) {
x->parent->color = _rb_tree_black;
y->color = _rb_tree_black;
x->parent->parent->color = _rb_tree_red;
x = x->parent->parent;
}
else {
if (x == x->parent->left) {
x = x->parent;
_rb_tree_rotate_right(x, root);
}
x->parent->color = _rb_tree_black;
x->parent->parent->color = _rb_tree_red;
_rb_tree_rotate_left(x->parent->parent, root);
}
}
}
root->color = _rb_tree_black;
}
2.4.4 红黑树的旋转操作
①:左旋:
Ⅰ.改变旋转点的右子节点的左子节点指向旋转点的右子节点
Ⅱ.改变旋转点及其2右子节点的位置,原本的旋转点的右子节点变为之前旋转点所在的位置,原本的旋转变为变化后的根节点的左子树。
Ⅲ.更新之前的结点
②:右旋:
Ⅰ:将插入点的父节点的颜色改为黑色,然后再将其爷爷结点变为红色,将其爷爷结点作为旋转点。
Ⅱ:改变旋转点的左子节点的右子节点指向旋转点的左子节点。
Ⅲ.改变旋转点及其左子节点的位置,原本的旋转点的左子节点变为之前旋转点的位置,然后将旧的旋转点变为新旋转点的右子树。
Ⅳ.更新之前的结点。
//****************************_rb_tree_rotate_left()************************************
inline void _rb_tree_rotate_left(_rb_tree_node_base* x, _rb_tree_node_base*& root) {
_rb_tree_node_base* y = x->right;
x->right = y->left;
if (y->left != 0) {
y->left->right = x;
}
y->parent = x->parent;
if (x == root)
root = y;
else if (x == x->parent->left)
x->parent->left = y;
else
x->parent->right = y;
y->left = x;
x->parent = y;
}
//****************************_rb_tree_rotate_right()************************************
inline void _rb_tree_rotate_right(_rb_tree_node_base* x, _rb_tree_node_base*& root) {
_rb_tree_node_base* y = x->left;
x->left = y->right;
if (y->right != 0)
y->right->parent = x;
y->parent = x->parent;
if (x == root) {
root = y;
}
else if (x == x->parent->right)
x->parent->right = y;
else
x->parent->left = y;
y->right = x;
x->parent = y;
}
2.4.5 删除结点后保持红黑树平衡
如果我们要删除的结点为红色,则就按照二叉查找树的删除即可,不会破坏树本身的性质,但是如果我们要删除的结点为黑色的话,并且该节点为左子节点(右子节点情况与下述相反):
①:兄弟结点若为红色,令父节点为红色,兄弟结点为黑色,然后进行旋转处理
②:兄弟结点若为黑色,并且兄弟结点的两个子结点都为黑色,令兄弟结点变为红色,令父亲结点变为当前结点继续处理。
③:兄弟结点为黑色,左子节点位红色,其右子节点位黑色,令兄弟结点为红色,兄弟结点的左子节点为黑色,以兄弟结点为旋转点右旋,继续处理。
④:兄弟结点为黑色,右子节点位红色,令兄弟结点为父亲结点的颜色,父亲结点为黑色,兄弟结点的右子结点为黑色,以父亲节点为旋转点左旋。
// 删除节点后使 rb tree 重新平衡,参数一为要删除的节点,参数二为根节点,参数三为最小节点,参数四为最大节点
//
// 参考博客: http://blog.csdn.net/v_JULY_v/article/details/6105630
// http://blog.csdn.net/v_JULY_v/article/details/6109153
template <class NodePtr>
NodePtr _rb_tree_erase_rebalance(NodePtr z, NodePtr& root, NodePtr& leftmost, NodePtr& rightmost)
{
// y 是可能的替换节点,指向最终要删除的节点
auto y = (z->left == nullptr || z->right == nullptr) ? z : rb_tree_next(z);
// x 是 y 的一个独子节点或 NIL 节点
auto x = y->left != nullptr ? y->left : y->right;
// xp 为 x 的父节点
NodePtr xp = nullptr;
// y != z 说明 z 有两个非空子节点,此时 y 指向 z 右子树的最左节点,x 指向 y 的右子节点。
// 用 y 顶替 z 的位置,用 x 顶替 y 的位置,最后用 y 指向 z
if (y != z)
{
z->left->parent = y;
y->left = z->left;
// 如果 y 不是 z 的右子节点,那么 z 的右子节点一定有左孩子
if (y != z->right)
{ // x 替换 y 的位置
xp = y->parent;
if (x != nullptr)
x->parent = y->parent;
y->parent->left = x;
y->right = z->right;
z->right->parent = y;
}
else
{
xp = y;
}
// 连接 y 与 z 的父节点
if (root == z)
root = y;
else if (rb_tree_is_lchild(z))
z->parent->left = y;
else
z->parent->right = y;
y->parent = z->parent;
mystl::swap(y->color, z->color);
y = z;
}
// y == z 说明 z 至多只有一个孩子
else
{
xp = y->parent;
if (x)
x->parent = y->parent;
// 连接 x 与 z 的父节点
if (root == z)
root = x;
else if (rb_tree_is_lchild(z))
z->parent->left = x;
else
z->parent->right = x;
// 此时 z 有可能是最左节点或最右节点,更新数据
if (leftmost == z)
leftmost = x == nullptr ? xp : rb_tree_min(x);
if (rightmost == z)
rightmost = x == nullptr ? xp : rb_tree_max(x);
}
// 此时,y 指向要删除的节点,x 为替代节点,从 x 节点开始调整。
// 如果删除的节点为红色,树的性质没有被破坏,否则按照以下情况调整(x为左子节点为例)
if (!rb_tree_is_red(y))
{ // x 为黑色时,调整,否则直接将 x 变为黑色即可
while (x != root && (x == nullptr || !rb_tree_is_red(x)))
{
if (x == xp->left)
{ // 如果 x 为左子节点
auto brother = xp->right;
if (rb_tree_is_red(brother))
{ // case 1
rb_tree_set_black(brother);
rb_tree_set_red(xp);
_rb_tree_rotate_left(xp, root);
brother = xp->right;
}
// case 1 转为为了 case 2、3、4 中的一种
if ((brother->left == nullptr || !rb_tree_is_red(brother->left)) &&
(brother->right == nullptr || !rb_tree_is_red(brother->right)))
{ // case 2
rb_tree_set_red(brother);
x = xp;
xp = xp->parent;
}
else
{
if (brother->right == nullptr || !rb_tree_is_red(brother->right))
{ // case 3
if (brother->left != nullptr)
rb_tree_set_black(brother->left);
rb_tree_set_red(brother);
_rb_tree_rotate_right(brother, root);
brother = xp->right;
}
// 转为 case 4
brother->color = xp->color;
rb_tree_set_black(xp);
if (brother->right != nullptr)
rb_tree_set_black(brother->right);
_rb_tree_rotate_left(xp, root);
break;
}
}
else // x 为右子节点,对称处理
{
auto brother = xp->left;
if (rb_tree_is_red(brother))
{ // case 1
rb_tree_set_black(brother);
rb_tree_set_red(xp);
_rb_tree_rotate_right(xp, root);
brother = xp->left;
}
if ((brother->left == nullptr || !rb_tree_is_red(brother->left)) &&
(brother->right == nullptr || !rb_tree_is_red(brother->right)))
{ // case 2
rb_tree_set_red(brother);
x = xp;
xp = xp->parent;
}
else
{
if (brother->left == nullptr || !rb_tree_is_red(brother->left))
{ // case 3
if (brother->right != nullptr)
rb_tree_set_black(brother->right);
rb_tree_set_red(brother);
_rb_tree_rotate_left(brother, root);
brother = xp->left;
}
// 转为 case 4
brother->color = xp->color;
rb_tree_set_black(xp);
if (brother->left != nullptr)
rb_tree_set_black(brother->left);
_rb_tree_rotate_right(xp, root);
break;
}
}
}
if (x != nullptr)
rb_tree_set_black(x);
}
return y;
}
3.map/multimap容器和set/multiset容器
以下容器有点类似于之前介绍的queue以及stack容器,类似于一种容器适配器,因此我们就不多介绍了。
3.1 set容器/multiset容器
set容器的特性是所有元素会被自动排序,set 的键值就是实值,实值就是键值,并且不允许有两个具有相同键值的值,我们不可以随意改变set容器中的值,因为都是按照元素大小排序好的,如果随意改变的话排序规则就会发生变化。
multiset容器与set容器稍微有所不同,不同之处在于它允许键值相同的元素存入容器中。
//****************************** set ****************************
template <class Key, class Compare = less<Key>, class Alloc = alloc>
class set
{
public:
typedef Key key_type;
typedef Key value_type;
typedef Compare key_compare;
typedef Compare value_compare;
private:
typedef rb_tree<key_type, value_type, identity<value_type>, key_compare, Alloc> rep_type;
rep_type t; //采用红黑树来表现set
public:
typedef typename rep_type::const_pointer pointer;
typedef typename rep_type::const_pointer const_pointer;
typedef typename rep_type::const_reference reference;
typedef typename rep_type::const_reference const_reference;
typedef typename rep_type::const_iterator iterator;
typedef typename rep_type::const_iterator const_iterator;
typedef typename rep_type::const_reverse_iterator reverse_iterator;
typedef typename rep_type::const_reverse_iterator const_reverse_iterator;
typedef typename rep_type::size_type size_type;
typedef typename rep_type::differnece_type difference_type;
//构造函数
//在set容器中 一定使用的是rb_tree的insert_unique()而不是insert_equal()
//multiset才使用rb_tree的insert_equal()
//因为set不允许重复的键值存在
set():t(Compare()){ }
explicit set(const Compare& comp) : t(comp) {}
template<class InputIterator>
set(InputIterator first, InputIterator last) :t(Compare()){
t.insert_unique(first, last);
}
template<class InputIterator>
set(InputIterator first, InputIterator last, const Compare& comp):t(comp){
t.insert_unique(first, last);
}
set(const set<Key, Compare, Alloc>& x):t(x.t) { }
set<Key, Compare, Alloc>& operator=(const set<Key, Compare, Alloc>& x) {
t = x.t;
return *this;
}
//元素操作
key_compare key_comp() const {
return t.key_comp();
}
value_compare value_comp() const {
return t.key_comp();
}
iterator begin() const {
return t.begin();
}
iterator end() const {
return t.end();
}
reverse_iterator rbegin() const {
return t.rbegin();
}
reverse_iterator rend() const {
return t.rend();
}
bool empty() const {
return t.empty();
}
size_type size() const {
return t.size();
}
size_type max_size() const {
return t.max_size();
}
void swap(set<Key, Compare, Alloc>& x) {
t.swap(x.t);
}
//insert/以及erase操作
typedef pair<iterator, bool> pair_iterator_bool;
pair<iterator, bool> insert(const value_type& x) {
pair<typename rep_type::iterator, bool> p = t.insert_unique(x);
return pair<iterator, bool>(p.first, p.second);
}
iterator insert(iterator position, const value_type& x) {
typedef typename rep_type::iterator rep_iterator;
return t.insert_unique((rep_iterator&)position, x);
}
template<class InputIterator>
void insert(InputIterator first, InputIterator last) {
t.insert_unique(first, last);
}
void erase(iterator position) {
typedef typename rep_type::iterator rep_iterator;
t.erase((rep_iterator&)position);
}
size_type erase(const key_type& x) {
return t.erase(x);
}
void erase(iterator first, iterator last) {
typedef typename rep_type::iterator rep_iterator;
t.erase((rep_iterator&)first, (rep_iterator&)last);
}
void clear() {
t.clear();
}
//set operations
iterator find(const key_type& x) const {
return t.find(x);
}
size_type count(const key_type& x) const {
return t.size(x);
}
iterator lower_bound(const key_type& x) const {
return t.lower_bound(x);
}
iterator upper_bound(const key_type& x) const {
return t.upper_bound(x);
}
pair<iterator, iterator> equal_range(const key_type& x) const {
return t.equal_range_unique(x);
}
friend bool operator==(const set& lhs, const set& rhs) { return lhs.t == rhs.t; }
friend bool operator< (const set& lhs, const set& rhs) { return lhs.t < rhs.t; }
};
// 重载比较操作符
template <class Key, class Compare, class Alloc>
bool operator==(const set<Key, Compare, Alloc>& lhs, const set<Key, Compare, Alloc>& rhs)
{
return lhs == rhs;
}
template <class Key, class Compare, class Alloc>
bool operator<(const set<Key, Compare, Alloc>& lhs, const set<Key, Compare, Alloc>& rhs)
{
return lhs < rhs;
}
template <class Key, class Compare, class Alloc>
bool operator!=(const set<Key, Compare, Alloc>& lhs, const set<Key, Compare, Alloc>& rhs)
{
return !(lhs == rhs);
}
template <class Key, class Compare, class Alloc>
bool operator>(const set<Key, Compare, Alloc>& lhs, const set<Key, Compare, Alloc>& rhs)
{
return rhs < lhs;
}
template <class Key, class Compare, class Alloc>
bool operator<=(const set<Key, Compare, Alloc>& lhs, const set<Key, Compare, Alloc>& rhs)
{
return !(rhs < lhs);
}
template <class Key, class Compare, class Alloc>
bool operator>=(const set<Key, Compare, Alloc>& lhs, const set<Key, Compare, Alloc>& rhs)
{
return !(lhs < rhs);
}
//******************************* multiset ****************************
template <class Key, class Compare = less<Key>, class Alloc = alloc>
class multiset
{
public:
typedef Key key_type;
typedef Key value_type;
typedef Compare key_compare;
typedef Compare value_compare;
private:
typedef rb_tree<key_type, value_type, identity<value_type>, key_compare, Alloc> rep_type;
rep_type t; //采用红黑树来表现set
public:
typedef typename rep_type::const_pointer pointer;
typedef typename rep_type::const_pointer const_pointer;
typedef typename rep_type::const_reference reference;
typedef typename rep_type::const_reference const_reference;
typedef typename rep_type::const_iterator iterator;
typedef typename rep_type::const_iterator const_iterator;
typedef typename rep_type::const_reverse_iterator reverse_iterator;
typedef typename rep_type::const_reverse_iterator const_reverse_iterator;
typedef typename rep_type::size_type size_type;
typedef typename rep_type::differnece_type difference_type;
//构造函数
//在set容器中 一定使用的是rb_tree的insert_unique()而不是insert_equal()
//multiset才使用rb_tree的insert_equal()
//因为set不允许重复的键值存在
multiset() :t(Compare()) { }
explicit multiset(const Compare& comp) : t(comp) {}
template<class InputIterator>
multiset(InputIterator first, InputIterator last) : t(Compare()) {
t.insert_equal(first, last);
}
template<class InputIterator>
multiset(InputIterator first, InputIterator last, const Compare& comp) : t(comp) {
t.insert_equal(first, last);
}
multiset(const multiset<Key, Compare, Alloc>& x) :t(x.t) { }
multiset<Key, Compare, Alloc>& operator=(const multiset<Key, Compare, Alloc>& x) {
t = x.t;
return *this;
}
//元素操作
key_compare key_comp() const {
return t.key_comp();
}
value_compare value_comp() const {
return t.key_comp();
}
iterator begin() const {
return t.begin();
}
iterator end() const {
return t.end();
}
reverse_iterator rbegin() const {
return t.rbegin();
}
reverse_iterator rend() const {
return t.rend();
}
bool empty() const {
return t.empty();
}
size_type size() const {
return t.size();
}
size_type max_size() const {
return t.max_size();
}
void swap(set<Key, Compare, Alloc>& x) {
t.swap(x.t);
}
//insert/以及erase操作
typedef pair<iterator, bool> pair_iterator_bool;
pair<iterator, bool> insert(const value_type& x) {
pair<typename rep_type::iterator, bool> p = t.insert_equal(x);
return pair<iterator, bool>(p.first, p.second);
}
iterator insert(iterator position, const value_type& x) {
typedef typename rep_type::iterator rep_iterator;
return t.insert_equal((rep_iterator&)position, x);
}
template<class InputIterator>
void insert(InputIterator first, InputIterator last) {
t.insert_equal(first, last);
}
void erase(iterator position) {
typedef typename rep_type::iterator rep_iterator;
t.erase((rep_iterator&)position);
}
size_type erase(const key_type& x) {
return t.erase(x);
}
void erase(iterator first, iterator last) {
typedef typename rep_type::iterator rep_iterator;
t.erase((rep_iterator&)first, (rep_iterator&)last);
}
void clear() {
t.clear();
}
//set operations
iterator find(const key_type& x) const {
return t.find(x);
}
size_type count(const key_type& x) const {
return t.size(x);
}
iterator lower_bound(const key_type& x) const {
return t.lower_bound(x);
}
iterator upper_bound(const key_type& x) const {
return t.upper_bound(x);
}
pair<iterator, iterator> equal_range(const key_type& x) const {
return t.equal_range_multi(x);
}
friend bool operator==(const multiset& lhs, const multiset& rhs) { return lhs.t == rhs.t; }
friend bool operator< (const multiset& lhs, const multiset& rhs) { return lhs.t < rhs.t; }
};
// 重载比较操作符
template <class Key, class Compare, class Alloc>
bool operator==(const multiset<Key, Compare, Alloc>& lhs, const multiset<Key, Compare, Alloc>& rhs)
{
return lhs == rhs;
}
template <class Key, class Compare, class Alloc>
bool operator<(const multiset<Key, Compare, Alloc>& lhs, const multiset<Key, Compare, Alloc>& rhs)
{
return lhs < rhs;
}
template <class Key, class Compare, class Alloc>
bool operator!=(const multiset<Key, Compare, Alloc>& lhs, const multiset<Key, Compare, Alloc>& rhs)
{
return !(lhs == rhs);
}
template <class Key, class Compare, class Alloc>
bool operator>(const multiset<Key, Compare, Alloc>& lhs, const multiset<Key, Compare, Alloc>& rhs)
{
return rhs < lhs;
}
template <class Key, class Compare, class Alloc>
bool operator<=(const multiset<Key, Compare, Alloc>& lhs, const multiset<Key, Compare, Alloc>& rhs)
{
return !(rhs < lhs);
}
template <class Key, class Compare, class Alloc>
bool operator>=(const multiset<Key, Compare, Alloc>& lhs, const multiset<Key, Compare, Alloc>& rhs)
{
return !(lhs < rhs);
}
3.2 map容器/multimap容器
map容器稍微有所不同,map中的所有元素都是pair,同时拥有实值和键值。我们不可以随意修改map的键值,因为这样会破坏map容器的排序规则,但是可以随意其实值。