m a p map map 是 C C C++ 标准模板库( S T L STL STL)中的一部分,它是一个关联式容器,用于存储键值对。每个元素都有一个唯一的键,并且可以通过键快速检索对应的值。 m a p map map 中的元素是按照键的特定顺序排列的,默认情况下是按照键的升序排列的,但这可以通过提供自定义的比较函数(仿函数)来改变。
文章目录
前言 —— pair 类型介绍
p a i r pair pair 类型的本质就是一个结构体,这个结构体将一对值耦合在一起。这些值可能具有不同的类型(模板类型),且可以通过其 p u b l i c public public 成员 f i r s t first first 和 s e c o n d second second 来访问各个值。更多细节可以去 C C C++ 官网查看 p a i r pair pair 类型的基本介绍 : p a i r pair pair 类型。

template <class T1, class T2>
struct pair
{
typedef T1 first_type;
typedef T2 second_type;
T1 first;
T2 second;
// 1.无参构造函数
pair()
: first(T1())
, second(T2())
{}
// 2.构造函数
pair(const T1& a, const T2& b)
: first(a)
, second(b)
{}
// 3.拷贝构造函数
template<class U, class V>
pair (const pair<U,V>& pr)
: first(pr.first)
, second(pr.second)
{}
};
m a p map map 底层的红黑树节点中的数据,就使用
pair<Key, T>存储键值对数据。
typedef pair<const Key, T> value_type; // Key值不可修改,只能修改value值
此外,为了方便传 p a i r pair pair 类型的参数,还提供了一个专门构造 p a i r pair pair 类型的函数( m a k e _ p a i r make\_pair make_pair):
template <class T1,class T2>
inline pair<T1,T2> make_pair (T1 x, T2 y)
{
return ( pair<T1,T2>(x,y) );
}
那么 p a i r pair pair 类型有什么用呢?为什么要使用 p a i r pair pair 类型?
在 C C C++ 中,函数返回值一次只能返回一个值,如果想传两个或多个值就可以传 p a i r pair pair 类型的变量,通过 f i r s t first first 和 s e c o n d second second 来指向这两个不同的值(多个值可以通过嵌套 p a i r pair pair 来实现)。
一、map 的介绍
m a p map map 系列根据容器是否支持插入相同元素(通过 K e y Key Key 值判断)而分为了 m a p map map(映射)和 m u l t i m a p multimap multimap(多重映射)。
m a p map map 其实就是用于存储由键值和映射值组合而成的元素,并按特定顺序进行存储的容器:

m u l t i m a p multimap multimap 其实就是用于存储由键值和映射值组合形成的元素,并遵循特定顺序进行存储的容器,其中多个元素可以具有等效的键值:

由于最常用的还是 m a p map map 容器,因此这里主要介绍的是 m a p map map,而 m u l t i m a p multimap multimap 和 m a p map map 只有在一些地方有略微的不同,稍注意一下即可。
m a p map map 的声明如下:
template < class Key, // map::key_type
class T, // map::mapped_type
class Compare = less<Key>, // map::key_compare
class Alloc = allocator<pair<const Key,T> > // map::allocator_type
> class map;
-
K e y Key Key 就是 m a p map map 底层关键字的类型。
-
T T T 是 m a p map map 底层 v a l u e value value 的类型。
-
m a p map map 默认要求 K e y Key Key 支持小于比较(
less<T>,升序排序),如果不支持或者需要的话可以自行实现仿函数传给第二个模板参数。 -
m a p map map 底层存储数据的内存是从空间配置器申请的,如果需要可以自己实现内存池,传给第三个模板参数。
注意:一般情况下,我们都不需要传后两个模板参数。
m a p map map 底层是用红黑树实现的,增删查改效率是 O ( l o g N ) O(logN) O(logN)(只支持 v a l u e value value 修改),迭代器遍历是走的中序,所以是按 k e y key key 有序顺序遍历的。
二、map 的使用(常用接口)
m a p map map 的成员类型( v a l u e _ t y p e value\_type value_type)为 p a i r pair pair 键值对。其中, p a i r pair pair 的第一个参数为 k e y key key 关键字( k e y _ t y p e key\_type key_type); p a i r pair pair 的第二个参数为 v a l u e value value 映射值( m a p p e d _ t y p e mapped\_type mapped_type)。
Member types
key_type -> The first template parameter (Key)
mapped_type -> The second template parameter (T)
value_type -> pair<const key_type, mapped_type> // key不可修改
1. 常见构造
| 构造 ( c o n s t r u c t o r ) (constructor) (constructor) 函数声明 | 接口说明 |
|---|---|
| m a p ( ) map() map() | 无参默认构造 |
| m a p ( c o n s t m a p & x ) map(const\ map\&\ x) map(const map& x) | 拷贝构造 |
| m a p ( I n p u t I t e r a t o r f i r s t , I n p u t I t e r a t o r l a s t ) map(InputIterator\ first, InputIterator\ last) map(InputIterator first,InputIterator last) | 使用迭代器区间构造 |
| m a p ( i n i t i a l i z e r _ l i s t < v a l u e _ t y p e > i l ) map (initializer\_list<value\_type> il) map(initializer_list<value_type>il) | 使用 i n i t i a l i z e r initializer initializer 列表构造 |
- 无参默认构造:
map<char, int> mp // 升序
map<char, int, greater<char>> // 降序
- 拷贝构造:
map<char, int, greater<char>> mp = { {'a',1},{'b',2},{'c',3} };
map<char, int> mp1(mp); // 升序
map<char, int, greater<char>> mp2(mp); // 降序
- 迭代器区间构造:
vector<pair<char,int>> v = { {'a',1},{'b',2},{'c',3} };
map<char, int> mp1(v.begin(),v.end()); // 升序
map<char, int, greater<int>> mp2(v.begin(),v.end()); // 降序
- i n i t i a l i z e r initializer initializer 列表构造:
map<char, int> mp1 = { {'a',1},{'b',2},{'c',3}}; // 升序
map<char, int, greater<char>> mp2 = { {'a',1},{'b',2},{'c',3}}; // 降序
2. iterator 的使用
| i t e r a t o r iterator iterator 的使用 | 接口说明 |
|---|---|
| b e g i n ( ) begin() begin() + + + e n d ( ) end() end() | 正向迭代器( i t e r a t o r iterator iterator) |
| r b e g i n ( ) rbegin() rbegin() + + + r e n d ( ) rend() rend() | 反向迭代器( r e v e r s e _ i t e r a t o r reverse\_iterator reverse_iterator) |
-
m a p map map 的支持正向和反向迭代遍历,遍历默认按 k e y key key 的升序顺序,因为底层是二叉搜索树,迭代器遍历走的是中序遍历。
-
支持迭代器就意味着支持范围 f o r for for。
-
m a p map map 支持修改 v a l u e value value 数据,不支持修改 k e y key key 数据,修改关键字数据,就破坏了底层搜索树的结构。
-
m a p map map 的迭代器是一个双向迭代器:
iterator -> a bidirectional iterator to const value_type。

map<char, int> mp = { {'a',1},{'b',2},{'c',3},{'d',4},{'e',5}};
// 1.正向迭代器
auto it = mp.begin();
while (it != mp.end())
{
cout << it->first << ":" << it->second << " ";
++it;
}
cout << endl;
// 2.反向迭代器
auto rit = mp.rbegin();
while (rit != mp.rend())
{
cout << rit->first << ":" << rit->second << " ";
++rit;
}
cout << endl;
// 3.范围for
for (const auto& e : mp)
{
cout << e.first << ":" << e.second << " ";
}
cout << endl;
输出:
a:1 b:2 c:3 d:4 e:5
e:5 d:4 c:3 b:2 a:1
a:1 b:2 c:3 d:4 e:5
3. 增删查
| m a p map map 增删查 | 接口说明 |
|---|---|
| i n s e r t insert insert | 插入 v a l val val 数据 |
| e r a s e erase erase | 删除 v a l val val 数据 |
| f i n d find find | 查找 v a l val val,返回 v a l val val 位置的迭代器(没找到返回 e n d ( ) end() end()) |
| c o u n t count count | 查找 v a l val val,返回 v a l val val 的个数 |
| l o w e r _ b o u n d lower\_bound lower_bound | 返回大于等于 v a l val val 位置的迭代器 |
| u p p e r _ b o u n d upper\_bound upper_bound | 返回大于 v a l val val 位置的迭代器 |
其中,增加数据的接口跟 s e t set set 所有不同, m a p map map 插入的是 p a i r pair pair 键值对数据,但是查找数据和删除数据的接口只和关键字 k e y key key 有关,因此跟 s e t set set 是完全类似的。
不过 f i n d find find 返回 i t e r a t o r iterator iterator,不仅可以确认 k e y key key 在不在,还能找到 k e y key key 映射的 v a l u e value value,同时通过迭代器还可以修改 v a l u e value value。
- 插入数据(
insert):
vector<pair<char, int>> v = { {'a',1},{'e',5},{'b',2} };
map<char, int> mp;
// 1.直接插入(pair)
mp.insert(make_pair('c', 3));
// 2.指定位置插入(pair)
mp.insert(mp.begin(), pair<char,int>('d',4));
// 3.迭代器区间插入
mp.insert(v.begin(), v.end());
// 4.initializer插入
mp.insert({ { 'f',6 }, { 'g',7 }, { 'h',8 } });
// 5.operator[]插入(最常用)
mp['i'] = 9;
for (const auto& e : mp) cout << e.first << ":" << e.second << " "; cout << endl;
输出:
a:1 b:2 c:3 d:4 e:5 f:6 g:7 h:8 i:9
- 查找 + 删除数据(
find + erase):
map<char, int> mp = { {'a',1},{'b',2},{'c',3},{'d',4},{'e',5} };
// 1.指定位置删除
mp.erase(mp.begin());
// 2.指定数据删除
mp.erase('d');
// 3.迭代器区间删除
auto it = mp.find('c'); // 返回值对应的迭代器(没找到就返回mp.end())
if (it != mp.end())
mp.erase(mp.begin(), it); // 前闭后开[mp.begin(),it)
for (const auto& e : mp) cout << e.first << ":" << e.second << " "; cout << endl;
输出:
c:30 e:5
lower_bound / upper_bound:
map<char, int> mp = { {'a',1},{'b',2},{'c',3},{'d',4},{'e',5} };
auto it1 = mp.lower_bound('b'); // 返回第一个key值 >= b的迭代器
auto it2 = mp.upper_bound('d'); // 返回第一个key值 > d的迭代器
// 删除[b,d]区间的数据
mp.erase(it1,it2);
for (const auto& e : mp) cout << e.first << ":" << e.second << " "; cout << endl;
输出:
a:1 e:5
4. 数据修改
m a p map map 只支持修改 m a p p e d _ t y p e mapped\_type mapped_type( v a l u e value value)数据,不支持修改 k e y key key 数据,修改关键字数据,就破坏了底层搜索树的结构。
- m a p map map 第一个支持修改的方式是通过迭代器,迭代器遍历时或者 f i n d find find 返回 k e y key key 所在的 i t e r a t o r iterator iterator 修改:
map<char, int> mp = { {'a',1},{'b',2},{'c',3},{'d',4},{'e',5} };
// 通过find找到迭代器可以修改其value值
auto fv = mp.find('c');
fv->second *= 10;
for (const auto& e : mp) cout << e.first << ":" << e.second << " "; cout << endl;
输出:
a:1 b:2 c:30 d:4 e:5
| m a p map map 数据修改 | 接口说明 |
|---|---|
| o p e r a t o r [ ] operator[\ ] operator[ ] | 修改 k e y key key 位置所对应的 v a l u e value value 数据 |
- m a p map map 还有一个非常重要的修改接口 o p e r a t o r [ ] operator[\ ] operator[ ],但是 o p e r a t o r [ ] operator[\ ] operator[ ] 不仅支持修改数据,还支持插入数据和查找数据,所以他是一个多功能复合接口:
map<char, int> mp = { {'a',1},{'b',2},{'c',3},{'d',4},{'e',5} };
// 最常用的方式:
// 1.修改数据
mp['c'] *= 10;
// 2.插入数据
mp['f'] = 6;
// 3.查找数据
cout << mp['b'] << endl;
for (const auto& e : mp) cout << e.first << ":" << e.second << " "; cout << endl;
输出:
2
a:1 b:2 c:30 d:4 e:5 f:6
需要注意从内部实现角度, m a p map map 这里把我们传统说的 v a l u e value value 值,给的是 T T T 类型, t y p e d e f typedef typedef 为 m a p p e d _ t y p e mapped\_type mapped_type。而 v a l u e _ t y p e value\_type value_type 是红黑树结点中存储的 p a i r pair pair 键值对值。日常使用我们还是习惯将这里的 T T T 映射值叫做 v a l u e value value。
-
如果 k k k 不在 m a p map map 中, i n s e r t insert insert 会插入 k k k 和 m a p p e d _ t y p e mapped\_type mapped_type 默认值,同时 [ ] [\ ] [ ] 返回结点中存储 m a p p e d _ t y p e mapped\_type mapped_type 值的引用,那么我们可以通过引用修改返回映射值。所以 [ ] [\ ] [ ] 具备了插入 + + + 修改功能。
-
如果 k k k 在 m a p map map 中, i n s e r t insert insert 会插入失败,但是 i n s e r t insert insert返回 p a i r pair pair 对象的 f i r s t first first 是指向 k e y key key 结点的迭代器,返回值同时 [ ] [\ ] [ ] 返回结点中存储 m a p p e d _ t y p e mapped\_type mapped_type 值的引用,所以 [ ] [\ ] [ ] 具备了查找 + + + 修改的功能。
pair<iterator,bool> insert (const value_type& val);
// operator的内部实现
mapped_type& operator[] (const key_type& k)
{
pair<iterator, bool> ret = insert({ k, mapped_type() });
iterator it = ret.first;
return it->second;
}
5. multimap 和 map 的差异
m u l t i m a p multimap multimap 和 m a p map map 的使用基本完全类似,主要区别点在于 m u l t i m a p multimap multimap 支持关键值 k e y key key 冗余。
- 那么 i n s e r t / f i n d / c o u n t / e r a s e insert/find/count/erase insert/find/count/erase 都围绕着支持关键值 k e y key key 冗余有所差异,比如 f i n d find find 时,有多个 k e y key key,返回中序第一个。
这里跟 s e t set set 和 m u l t i s e t multiset multiset 完全一样,在此不再重复介绍,有兴趣可以参考这篇博客:【STL】 s e t set set。
- 其次就是 m u l t i m a p multimap multimap 不支持 [ ] [\ ] [ ],因为支持 k e y key key 冗余, [ ] [\ ] [ ] 就只能支持插入了,不能支持修改。
三、map 的模拟实现
1. STL 中的 map 源码
S G I − S T L 30 SGI-STL\ 30 SGI−STL 30 版本源代码, m a p map map 容器的实现需要用到红黑树,对于红黑树这个数据结构的详细介绍,可以参考我的这篇博客:【数据结构】红黑树。
- 因此库里 m a p map map 容器的头文件包含了 s t l _ t r e e . h stl\_tree.h stl_tree.h, s t l _ m a p . h stl\_map.h stl_map.h 和 s t l _ m u l t i m a p . h stl\_multimap.h stl_multimap.h:
// map
#ifndef __SGI_STL_INTERNAL_TREE_H
#include <stl_tree.h>
#endif
#include <stl_map.h>
#include <stl_multimap.h>
- s t l _ m a p . h stl\_map.h stl_map.h:
// stl_map.h
template <class Key, class T, class Compare = less<Key>, class Alloc = alloc>
class map
{
public:
// typedefs:
typedef Key key_type;
typedef T mapped_type;
typedef pair<const Key, T> value_type;
private:
typedef rb_tree<key_type, value_type,
select1st<value_type>, key_compare, Alloc> rep_type;
rep_type t; // red-black tree representing map
};
2. map 的迭代器
m a p map map 的 i t e r a t o r iterator iterator 不支持修改 k e y key key 但是可以修改 v a l u e value value,我们把 m a p map map 的第二个模板参数 p a i r pair pair 的第一个参数改成 c o n s t K const\ K const K 即可。
typedef typename RBTree<K, pair<const K, V>, mapKeyOfT>::iterator iterator;
typedef typename RBTree<K, pair<const K, V>, mapKeyOfT>::const_iterator const_iterator;
RBTree<K, pair<const K, V>, mapKeyOfT> _t;
3. map 支持 operator[]
m a p map map 要支持 o p e r a t o r [ ] operator[\ ] operator[ ] 主要需要修改 i n s e r t insert insert 返回值支持,修改 R B t r e e RBtree RBtree 中的 i n s e r t insert insert 返回值为
pair<iterator, bool> insert(const T& data)即可。
有了 i n s e r t insert insert 支持 o p e r a t o r [ ] operator[\ ] operator[ ] 实现就很简单了:
V& operator[](const K& key)
{
pair<iterator, bool> ret = insert(make_pair(key, V()));
return ret.first->second;
}
4. 模拟实现 map
由于 m a p map map 属于 C C C++ S T L STL STL 容器(模板类),因此, m a p map map 声明和定义都要写到一个文件中。又因为 m a p map map 的底层结构是红黑树,因此迭代器直接使用红黑树的迭代器即可。
总共分为三个文件:红黑树类直接使用我们之前泛型封装好的 r b _ t r e e . h rb\_tree.h rb_tree.h(底层数据结构); m a p . h map.h map.h 用来存放 m a p map map 的定义和实现; t e s t . c p p test.cpp test.cpp 用来测试。
注意:这里两个文件中的 m a p map map 都是自己定义的,为了和 s t d : : m a p std::map std::map 作区分,我们要单独创建一个命名空间,这里我用的是 n a m e s p a c e y b c namespace\ ybc namespace ybc 。
- r b _ t r e e . h rb\_tree.h rb_tree.h:
#pragma once
#include<iostream>
using namespace std;
namespace ybc
{
// 枚举值表示颜色
enum color
{
red,
black
};
template<class T>
struct RBTreeNode
{
T _data; // 每个结点存储的值
RBTreeNode<T>* _left; // 左子树
RBTreeNode<T>* _right; // 右子树
RBTreeNode<T>* _parent; // 父结点
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;
Node* _root;
RBTreeIterator(Node* node, Node* root)
:_node(node)
, _root(root)
{}
self& operator ++ ()
{
if (_node->_right)
{
// 右不为空,右子树最左结点就是下一个结点
Node* lm = _node->_right;
while (lm->_left)
{
lm = lm->_left;
}
_node = lm;
}
else
{
// 右为空,孩子是父亲的左的那个祖先就是下一个结点
Node* cur = _node;
Node* parent = cur->_parent;
while (parent && cur != parent->_left)
{
cur = parent;
parent = cur->_parent;
}
_node = parent;
}
return *this;
}
self& operator -- ()
{
if (_node == nullptr) // end()
{
// 整棵树的最右结点就是end()的上一个结点
Node* rm = _root;
while (rm && rm->_right)
{
rm = rm->_right;
}
_node = rm;
}
else if (_node->_left)
{
// 左不为空,左子树的最右结点就是上一个结点
Node* rm = _node->_left;
while (rm->_right)
{
rm = rm->_right;
}
_node = rm;
}
else
{
// 左为空,孩子是父亲右的那个祖先就是上一个结点
Node* cur = _node;
Node* parent = cur->_parent;
while (parent && cur != parent->_right)
{
cur = parent;
parent = cur->_parent;
}
_node = parent;
}
return *this;
}
Ref operator * ()
{
return _node->_data;
}
Ptr operator -> ()
{
return &_node->_data;
}
bool operator != (const self& s) const
{
return _node != s._node;
}
bool operator == (const self& s) const
{
return _node == s._node;
}
};
template<class K, class T, class KeyOfT>
class RBTree
{
typedef RBTreeNode<T> node;
KeyOfT kot;
public:
typedef RBTreeIterator<T, T&, T*> iterator;
typedef RBTreeIterator<T, const T&, const T*> const_iterator;
iterator begin()
{
node* lm = _root;
while (lm && lm->_left)
{
lm = lm->_left;
}
return iterator(lm, _root);
}
iterator end()
{
return iterator(nullptr, _root);
}
const_iterator cbegin() const
{
node* lm = _root;
while (lm && lm->_left)
{
lm = lm->_left;
}
return const_iterator(lm, _root);
}
const_iterator cend() const
{
return const_iterator(nullptr, _root);
}
RBTree() = default;
~RBTree()
{
destroy(_root);
_root = nullptr;
}
pair<iterator, bool> insert(const T& data)
{
if (_root == nullptr)
{
_root = new node(data);
_root->_col = black;
return make_pair(iterator(nullptr, _root), true);
}
node* parent = nullptr;
node* cur = _root;
while (cur)
{
if (kot(data) < kot(cur->_data))
{
parent = cur;
cur = cur->_left;
}
else if (kot(data) > kot(cur->_data))
{
parent = cur;
cur = cur->_right;
}
else
{
return make_pair(iterator(cur, _root), false);
}
}
cur = new node(data);
node* newnode = cur;
if (kot(data) < kot(parent->_data))
{
parent->_left = cur;
}
else
{
parent->_right = cur;
}
cur->_parent = parent;
// 维持平衡操作
while (parent && parent->_col == red) // 如果父亲是红,说明出现了连续的红色结点
{
node* grandparent = parent->_parent;
if (parent == grandparent->_left)
{
node* uncle = grandparent->_right;
/*
g
/ \
p u
*/
if (uncle && uncle->_col == red) // 情况一:u 存在且为红色
{
// 变色
grandparent->_col = red;
parent->_col = uncle->_col = black;
// 继续向上更新
cur = grandparent;
parent = cur->_parent;
}
else // 情况二:u 存在且为黑色 或者 u 不存在
{
// 旋转 + 变色
if (cur == parent->_left)
{
/* 1. 单旋
g p
/ \ / \
p u -> c g
/ \
c u
*/
rotateR(grandparent);
// 变色
parent->_col = black;
grandparent->_col = red;
}
else
{
/* 2. 双旋
g c
/ \ / \
p u -> p g
\ \
c u
*/
rotateL(parent);
rotateR(grandparent);
// 变色
cur->_col = black;
grandparent->_col = red;
}
break;
}
}
else
{
node* uncle = grandparent->_left;
/*
g
/ \
u p
*/
if (uncle && uncle->_col == red) // 情况一:u 存在且为红色
{
// 只变色
grandparent->_col = red;
uncle->_col = parent->_col = black;
// 继续向上更新
cur = grandparent;
parent = cur->_parent;
}
else // 情况二:u 存在且为黑色 或者 u 不存在
{
// 旋转 + 变色
if (cur == parent->_right)
{
/* 1. 单旋
g p
/ \ / \
u p -> g c
\ /
c u
*/
rotateL(grandparent);
// 变色
parent->_col = black;
grandparent->_col = red;
}
else
{
/* 2. 双旋
g c
/ \ / \
u p -> g p
/ /
c u
*/
rotateR(parent);
rotateL(grandparent);
// 变色
cur->_col = black;
grandparent->_col = red;
}
break;
}
}
}
_root->_col = black;
return make_pair(iterator(newnode, _root), true);
}
iterator find(const K& key)
{
node* cur = _root;
while (cur)
{
if (key < kot(cur->_data))
{
cur = cur->_left;
}
else if (key > kot(cur->_data))
{
cur = cur->_right;
}
else
{
return iterator(cur, _root);
}
}
return iterator(nullptr, _root);
}
private:
void rotateL(node* parent)
{
node* subR = parent->_right;
node* subRL = subR->_left;
node* pParent = parent->_parent;
// 旋转核心逻辑
subR->_left = parent;
parent->_right = subRL;
if (pParent == nullptr) // parent == _root
_root = subR;
else if (pParent->_left == parent)
pParent->_left = subR;
else
pParent->_right = subR;
// 处理_parent
if (subRL)
subRL->_parent = parent;
parent->_parent = subR;
subR->_parent = pParent;
}
void rotateR(node* parent)
{
node* subL = parent->_left;
node* subLR = subL->_right;
node* pParent = parent->_parent;
// 旋转核心逻辑
subL->_right = parent;
parent->_left = subLR;
if (pParent == nullptr) // parent == _root
_root = subL;
else if (pParent->_left = parent)
pParent->_left = subL;
else
pParent->_right = subL;
// 处理_parent
if (subLR)
subLR->_parent = parent;
parent->_parent = subL;
subL->_parent = pParent;
}
void destroy(node* root)
{
if (root == nullptr)
return;
destroy(root->_left);
destroy(root->_right);
delete root;
}
node* _root = nullptr;
};
}
- m a p . h map.h map.h:
#pragma once
#include"rb_tree.h"
using namespace std;
namespace ybc
{
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<const K, V>, mapKeyOfT>::iterator iterator;
typedef typename RBTree<K, pair<const K, V>, mapKeyOfT>::const_iterator const_iterator;
iterator begin()
{
return _t.begin();
}
iterator end()
{
return _t.end();
}
const_iterator cbegin() const
{
return _t.cbegin();
}
const_iterator cend() const
{
return _t.cend();
}
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<const K, V>, mapKeyOfT> _t;
};
}
- t e s t . c p p test.cpp test.cpp:
#include"set.h"
namespace ybc
{
void test1()
{
set<int> s;
s.insert(5);
s.insert(1);
s.insert(3);
s.insert(4);
s.insert(2);
auto it = s.begin();
while (it != s.end())
{
cout << *it << " ";
++it;
}
cout << endl;
}
template<class T>
void print(set<T>& s)
{
auto it = s.begin();
while (it != s.end())
{
cout << *it << " ";
++it;
}
cout << endl;
}
void test2()
{
set<int> s;
int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
for (auto e : a)
{
s.insert(e);
}
for (auto e : s)
{
cout << e << " ";
}
cout << endl;
print(s);
}
}
int main()
{
//ybc::test1();
ybc::test2();
return 0;
}
总结
m a p map map 是一个关联式容器,其特性是,所有元素都会根据元素的键值自动排序,并且其所有元素都是 p a i r pair pair,同时拥有键值( k e y key key)和实值( v a l u e value value)。
m a p map map 的底层数据结构采用的是红黑树,并根据键值是否冗余分为了 m a p map map 和 m u l t i m a p multimap multimap,但 m a p map map 重载了 [ ] [\ ] [ ],使其非常方便好用,其不仅可以通过迭代器进行访问和修改元素(只能修改 v a l u e value value,不能修改 k e y key key),还能直接使用 [ ] [\ ] [ ] 进行访问和修改。
红黑树的本质是一棵自平衡二叉搜索树,增删查的时间复杂度都是 O ( log N ) O(\log N) O(logN),因此 m a p map map 的效率很高。


1990

被折叠的 条评论
为什么被折叠?



