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

标签: c++11
580人阅读 评论(0) 收藏 举报
分类:

文章内容为网络搜集内容

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_findstd::countstd::count_ifstd::findstd::find_ifstd::find_endstd::find_first_ofstd::searchstd::search_nstd::equalstd::mismatch

二分查找(Binary search)

std::lower_boundstd::upper_boundstd::equal_rangestd::binary_search

集合(Set)操作

std::includesstd::set_differencestd::set_intersectionstd::set_unionstd::set_symmetric_difference

最大与最小

std::min_elementstd::max_element

字典序比较

std::lexicographical_compare

排列生成器

std::next_permutationstd::prev_permutation

其它操作

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

代码示例

示例一:

#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;
}
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:346860次
    • 积分:3876
    • 等级:
    • 排名:第8495名
    • 原创:91篇
    • 转载:5篇
    • 译文:1篇
    • 评论:53条
    博客专栏
    我的开源项目
    最新评论