文章内容为网络搜集内容
std::map
映射表(Map)容器是一个按特定顺序存储以键值对组合而成的元素的关联容器
// <map>
template < class Key,
class T,
class Compare = less<Key>,
class Alloc = allocator<pair<const Key,T> >
> class map;
容器特性:
关联(Associative)
关联容器中的元素是通过主键(Key)而不是它们在容器中的绝对位置来引用的。
有序(Ordered)
容器中的元素在任意时刻都遵循一个严格排序规则。所有插入的元素都按该排序规则获得对应的位置。
映射(Map)
每个元素为一个值(Mapped value)绑定一个键(Key):以主键来标志主要内容等于被映射值的元素。
键唯一(Unique keys)
容器中不存在两个元素有相同的主键。
能够感知内存分配器的(Allocator-aware)
容器使用一个内存分配器对象来动态地处理它的存储需求。
模板参数
Key
主键的类型。
在类模板内部,使用其别名为 key_type 的成员类型。
T
被映射的值的类型。
在类模板内部,使用其别名为 mapped_type 的成员类型。
Compare
一个二元谓词,以两个元素的主键为参数返回一个 bool 值。
可以是函数指针(Function pointer)类型或函数对象(Function object)类型。
在类模板内部,使用其别名为 key_compare 的成员类型。
Alloc
容器内部用来管理内存分配及释放的内存分配器的类型。
这个参数是可选的,它的默认值是 std::allocator,这个是一个最简单的非值依赖的(Value-independent)内存分配器。在类模板内部,使用其别名为 allocator_type 的成员类型。
详细说明
在一个映射表容器中,主键通常被用来排序及唯一标志一个元素,而被映射的值保存了与该主键关联的内容。主键与被映射值的类型可以不同,在模板内部,这两种类型合并绑定成成员类型 value_type。由上述描述可知,value_type 是一个双元组类型(Pair type),具体定义如下:
typedef pair<const Key, T> value_type;
map 容器中的所有元素都是按由类型为 Compare 的比较对象指定的严格弱序规则排序的。
在用主键访问单个元素时,map 容器通常比 unordered_map 容器低效,但 map 容器允许按顺序直接对某个子集进行迭代。
map 容器通常被实现为一个二叉搜索树(及其变型),该数据结构具有对数据自动排序的功能。
在所有关联容器中,map 容器唯一具有的一个特点:实现了直接访问操作符(operator[]),使得可以直接访问被映射的值。
map 容器支持双向迭代
成员类型
成员类型 | 定义 |
---|---|
key_type | 第一个模板参数 Key |
mapped_type | 第二个模板参数 T |
value_type | std::pair |
size_type | 无符号整数类型(通常为 size_t) |
difference_type | 有符号整数类型(通常为 ptrdiff_t) |
key_compare | 第三个模板参数 Compare |
allocator_type | 第四个模板参数 Alloc |
reference | Allocator::reference 已弃用 value_type& C++11 |
const_reference | Allocator::const_reference 已弃用 const value_type& C++11 |
pointer | Allocator::pointer 已弃用 std::allocator_traits::pointer C++11 |
const_pointer | Allocator::const_pointer 已弃用 std::allocator_traits::const_pointer C++11 |
iterator | 双向迭代器 |
const_iterator | 常双向迭代器 |
reverse_iterator | std::reverse_iterator |
const_reverse_iterator | std::reverse_iterator |
成员函数
(constructor) 创建 map
(destructor) 释放 map
operator= 值赋操作
Iterators:
begin 返回指向容器起始位置的迭代器(iterator)
end 返回指向容器末尾位置的迭代器
rbegin 返回指向容器逆序起始位置的逆序迭代器(reverse_iterator)
rend 返回指向容器逆序末尾位置的逆序迭代器
cbegin C++11 返回指向容器起始位置的常迭代器(const_iterator)
cend C++11 返回指向容器末尾位置的常迭代器
crbegin C++11 返回指向容器逆序起始位置的常逆序迭代器(const_reverse_iterator)
crend C++11 返回指向容器逆序末尾位置的常逆序迭代器
Capacity:
size 返回有效元素个数
max_size 返回 map 支持的最大元素个数
empty 判断是否为空
Element access:
operator[] 访问元素
at C++11 访问元素
Modifiers:
insert 插入元素
erase 删除元素
swap 交换内容
clear 清空内容
emplace C++11 构造及插入一个元素
emplace_hint C++11 按提示构造及插入一个元素
Observers:
key_comp 返回键比较对象
value_comp 返回值比较对象
Operations:
find 通过给定主键查找元素
count 返回匹配给定主键的元素的个数
lower_bound 返回指向容器中第一个主键等于给定搜索值或在给定搜索值之后的元素的迭代器
upper_bound 返回指向容器中第一个主键在给定搜索值之后的元素的迭代器
equal_range 返回值匹配给定搜索值的元素组成的范围
Allocator:
get_allocator 获得内存分配器
非成员函数
operator==、operator!=、operator<、operator<=、operator>、operator>=
关系操作符
std::swap 交换两个映射表容器的内容
算法相关
搜索算法
std::adjacent_find、std::count、
std::count_if、std::find、
std::find_if、std::find_end、
std::find_first_of、std::search、
std::search_n、std::equal、
std::mismatch
二分查找(Binary search)
std::lower_bound、std::upper_bound、
std::equal_range、std::binary_search
集合(Set)操作
std::includes、std::set_difference、
std::set_intersection、std::set_union、
std::set_symmetric_difference
最大与最小
std::min_element、std::max_element
字典序比较
std::lexicographical_compare
排列生成器
std::next_permutation、
std::prev_permutation
其它操作
std::all_of、std::any_of、std::none_of、
std::for_each、std::copy、std::copy_if、
std::copy_n、std::copy_backward、
std::move、std::move_backward、
std::swap_ranges、std::iter_swap、
std::transform、std::replace、
std::replace_if、std::replace_copy、
std::replace_copy_if、std::fill、
std::fill_n、std::generate、
std::generate_n、std::remove、
std::remove_if、std::unique、
std::unique_copy、std::reverse、
std::reverse_copy、std::rotate、
std::rotate_copy、std::random_shuffle、
std::shuffle、std::partition、
std::is_partitioned、std::stable_partition、
std::partition_copy、std::merge
代码示例
示例一:
#include <map>
#include <iostream>
namespace ClassFoo{
void PrintIntDoubleMap(std::map<int,double>& m, char* pre) {
std::map<int,double>::iterator it;
std::cout << pre;
for ( it = m.begin(); it != m.end(); it++ )
std::cout << "(" << it->first << "," << it->second << ") ";
std::cout << std::endl;
}
void MapExample1() {
std::map<int,double> foo1;
// operator[]在主键不存在时,自动创建
foo1[0] = 32.8;
// 普通插入
foo1.insert(std::map<int,double>::value_type(1, 33.2));
// 带暗示插入,std::pair<int,double>等价于上述的
// std::map<int,double>::value_type
foo1.insert(foo1.end(),std::pair<int,double>(2,35.8));
// 插入一个范围
std::map<int,double> foo2;
foo2.insert(std::map<int,double>::value_type(3, 36.4));
foo2.insert(std::map<int,double>::value_type(4, 37.8));
foo2.insert(std::map<int,double>::value_type(5, 35.4));
foo1.insert(foo2.begin(),foo2.end());
PrintIntDoubleMap(foo1,"插入元素后的foo1:");
// 查找主键4
std::map<int,double>::iterator it;
it = foo1.find(4);
if( it != foo1.end() )
{
std::cout << "foo1.find(4):";
std::cout << "(" << it->first << "," << it->second << ")"
<< std::endl;
}
// 删除上述找到的元素
if( it != foo1.end() )
{
foo1.erase(it);
}
PrintIntDoubleMap(foo1,"删除主键为4的元素后的foo1:");
// 遍历删除主键为2的元素
for(it = foo1.begin();it != foo1.end();it++)
{
//遍历删除主键等于2
//注意,删除元素会使迭代范围发生变化
if(it->first == 2)
{
foo1.erase(it);
break;
}
}
PrintIntDoubleMap(foo1,"删除主键为2的元素后的foo1:");
foo1.clear();
PrintIntDoubleMap(foo1,"清空后的foo1:");
}
}
int main( )
{
ClassFoo::MapExample1();
return 0;
}
输出:
插入元素后的foo1:(0,32.8)(1,33.2)(2,35.8)(3,36.4)(4,37.8)(5,35.4)
foo1.find(4):(4,37.8)
删除主键为4的元素后的foo1:(0,32.8)(1,33.2)(2,35.8)(3,36.4)(5,35.4)
删除主键为2的元素后的foo1:(0,32.8)(1,33.2)(3,36.4)(5,35.4)
清空后的foo1:
示例二:c++11
涉及的成员函数 map::at、map::emplace 及 map::emplace_hint 是 C++11 中新增的:
#include <map>
#include <iostream>
namespace ClassFoo{
void PrintIntDoubleMap(std::map<int,double>& m, char* pre) {
std::map<int,double>::iterator it;
std::cout << pre;
for ( it = m.begin(); it != m.end(); it++ )
std::cout << "(" << it->first << "," << it->second << ")";
std::cout << std::endl;
}
void MapExample2() {
std::map<int,double> foo1;
// operator[]在主键不存在时,自动创建
foo1[0] = 32.8;
// 普通插入
foo1.insert(std::map<int,double>::value_type(1, 33.2));
// 带暗示插入,std::pair<int,double>等价于上述的
// std::map<int,double>::value_type
foo1.insert(foo1.end(),std::pair<int,double>(2,35.8));
// 插入一个范围
std::map<int,double> foo2;
foo2.insert(std::map<int,double>::value_type(3, 36.4));
foo2.insert(std::map<int,double>::value_type(4, 37.8));
foo2.insert(std::map<int,double>::value_type(5, 35.4));
foo1.insert(foo2.begin(),foo2.end());
// 放置插入
foo1.emplace(6,38.0);
// 带暗示的放置插入
foo1.emplace_hint(foo1.end(),7,36.4);
PrintIntDoubleMap(foo1,"插入元素后的foo1:");
// 修改键值为5的元素中的被
foo1.at(5) = 100.1;
PrintIntDoubleMap(foo1,"修改键值为5的元素后的foo1:");
// 查找主键4
std::map<int,double>::iterator it;
it = foo1.find(4);
if( it != foo1.end() )
{
std::cout << "foo1.find(4):";
std::cout << "(" << it->first << "," << it->second << ")"
<< std::endl;
}
// 删除上述找到的元素
if( it != foo1.end() )
{
foo1.erase(it);
}
PrintIntDoubleMap(foo1,"删除主键为4的元素后的foo1:");
// 遍历删除主键为2的元素
for(it = foo1.begin();it != foo1.end();it++)
{
//遍历删除主键等于2
//注意,删除元素会使迭代范围发生变化
if(it->first == 2)
{
foo1.erase(it);
break;
}
}
PrintIntDoubleMap(foo1,"删除主键为2的元素后的foo1:");
foo1.clear();
PrintIntDoubleMap(foo1,"清空后的foo1:");
}
}
int main( )
{
ClassFoo::MapExample2();
return 0;
}
输出:
插入元素后的foo1:(0,32.8)(1,33.2)(2,35.8)(3,36.4)(4,37.8)(5,35.4)(6,38)(7,36.4)
修改键值为5的元素后的foo1:(0,32.8)(1,33.2)(2,35.8)(3,36.4)(4,37.8)(5,100.1)(6,38)(7,36.4)
oo1.find(4):(4,37.8)
删除主键为4的元素后的foo1:(0,32.8)(1,33.2)(2,35.8)(3,36.4)(5,100.1)(6,38)(7,36.4)
删除主键为2的元素后的foo1:(0,32.8)(1,33.2)(3,36.4)(5,100.1)(6,38)(7,36.4)
清空后的foo1:
示例三:
主键及被映射值都为对象。下面这个例子实现了最简单的电话簿功能:
#include <iostream>
#include <map>
#include <string>
namespace ClassFoo{
using namespace std;
class name {
string str;
public:
name() {}
name(string s) { str = s; }
string& get() { return str; }
};
bool operator<(name a, name b)
{
return a.get() < b.get();
}
class phoneNum {
string str;
public:
phoneNum() { }
phoneNum(string s) { str = s; }
string& get() { return str; }
};
void MapExample3() {
map<name, phoneNum> directory;
directory.insert(pair<name, phoneNum>(name("A"), phoneNum("555-1111")));
directory.insert(pair<name, phoneNum>(name("B"), phoneNum("555-2222")));
directory.insert(pair<name, phoneNum>(name("C"), phoneNum("555-3333")));
directory.insert(pair<name, phoneNum>(name("D"), phoneNum("555-4444")));
map<name, phoneNum>::iterator p;
p = directory.find(name("A"));
if(p != directory.end())
cout << "A的电话号码为: " << p->second.get() << endl;
else
cout << "未发现A的电话号码" <<endl;
}
}
int main()
{
ClassFoo::MapExample3();
return 0;
}