【c++】映射表std::map

文章内容为网络搜集内容

std::map

映射表(Map)容器是一个按特定顺序存储以键值对组合而成的元素的关联容器

// <map>
template < class Key,
    class T,
    class Compare = less<Key>,
    class Alloc = allocator<pair<const Key,T> >
> class map;

  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

容器特性:

关联(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;
  
  
  • 1

map 容器中的所有元素都是按由类型为 Compare 的比较对象指定的严格弱序规则排序的。

在用主键访问单个元素时,map 容器通常比 unordered_map 容器低效,但 map 容器允许按顺序直接对某个子集进行迭代。

map 容器通常被实现为一个二叉搜索树(及其变型),该数据结构具有对数据自动排序的功能。

在所有关联容器中,map 容器唯一具有的一个特点:实现了直接访问操作符(operator[]),使得可以直接访问被映射的值。

map 容器支持双向迭代

成员类型

成员类型定义
key_type第一个模板参数 Key
mapped_type第二个模板参数 T
value_typestd::pair
size_type无符号整数类型(通常为 size_t)
difference_type有符号整数类型(通常为 ptrdiff_t)
key_compare第三个模板参数 Compare
allocator_type第四个模板参数 Alloc
referenceAllocator::reference 已弃用 value_type& C++11
const_referenceAllocator::const_reference 已弃用 const value_type& C++11
pointerAllocator::pointer 已弃用 std::allocator_traits::pointer C++11
const_pointerAllocator::const_pointer 已弃用 std::allocator_traits::const_pointer C++11
iterator双向迭代器
const_iterator常双向迭代器
reverse_iteratorstd::reverse_iterator
const_reverse_iteratorstd::reverse_iterator

成员函数

(constructor)   创建 map
(destructor)    释放 map
operator=   值赋操作
  
  
  • 1
  • 2
  • 3

​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 返回指向容器逆序末尾位置的常逆序迭代器
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

Capacity:

size    返回有效元素个数
max_size    返回 map 支持的最大元素个数
empty   判断是否为空
  
  
  • 1
  • 2
  • 3

Element access:

operator[]  访问元素
at C++11    访问元素
  
  
  • 1
  • 2

Modifiers:

insert  插入元素
erase   删除元素
swap    交换内容
clear   清空内容
emplace C++11   构造及插入一个元素
emplace_hint C++11  按提示构造及插入一个元素
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Observers:

key_comp    返回键比较对象
value_comp  返回值比较对象
  
  
  • 1
  • 2

Operations:

find    通过给定主键查找元素
count   返回匹配给定主键的元素的个数
lower_bound 返回指向容器中第一个主键等于给定搜索值或在给定搜索值之后的元素的迭代器
upper_bound 返回指向容器中第一个主键在给定搜索值之后的元素的迭代器
equal_range 返回值匹配给定搜索值的元素组成的范围
  
  
  • 1
  • 2
  • 3
  • 4
  • 5

Allocator:

get_allocator   获得内存分配器
  
  
  • 1

非成员函数

operator==、operator!=、operator<、operator<=、operator>、operator>=
  
  
  • 1

关系操作符

std::swap   交换两个映射表容器的内容
  
  
  • 1

算法相关

搜索算法

std::adjacent_findstd::countstd::count_ifstd::findstd::find_ifstd::find_endstd::find_first_ofstd::searchstd::search_nstd::equalstd::mismatch
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

二分查找(Binary search)

std::lower_boundstd::upper_boundstd::equal_rangestd::binary_search
  
  
  • 1
  • 2

集合(Set)操作

std::includesstd::set_differencestd::set_intersectionstd::set_unionstd::set_symmetric_difference
  
  
  • 1
  • 2
  • 3

最大与最小

std::min_elementstd::max_element
  
  
  • 1

字典序比较

std::lexicographical_compare
  
  
  • 1

排列生成器

std::next_permutationstd::prev_permutation
  
  
  • 1
  • 2

其它操作

std::all_ofstd::any_ofstd::none_ofstd::for_eachstd::copystd::copy_ifstd::copy_nstd::copy_backward、
​std::movestd::move_backwardstd::swap_rangesstd::iter_swapstd::transformstd::replace、
​std::replace_ifstd::replace_copystd::replace_copy_ifstd::fillstd::fill_nstd::generatestd::generate_nstd::removestd::remove_ifstd::uniquestd::unique_copystd::reverse、
​std::reverse_copystd::rotatestd::rotate_copystd::random_shufflestd::shufflestd::partitionstd::is_partitionedstd::stable_partition、
​std::partition_copystd::merge
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

代码示例

示例一:

#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;
}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71

输出:

插入元素后的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:
  
  
  • 1
  • 2
  • 3
  • 4
  • 5

示例二: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;
}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78

输出:

插入元素后的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:
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

示例三:
主键及被映射值都为对象。下面这个例子实现了最简单的电话簿功能:

#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;
}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值