关闭

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

标签: c++11
956人阅读 评论(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
查看评论

C++ 映射map的使用心得

在写获取时间的函数时,想到映射的变量,心血来潮就查了些资料。map的功能: 1. 自动建立Key - value的对应。key 和 value可以是任意你需要的类型。 2. 根据key值快速查找记录,查找的复杂度基本是Log(N),如果有1000个记录,最多查找10次,1,000,000个记...
  • BlueCY
  • BlueCY
  • 2017-04-02 13:35
  • 1587

C++ Map常见用法说明

C++中map提供的是一种键值对容器,里面的数据都是成对出现的,如下图:每一对中的第一个值称之为关键字(key),每个关键字只能在map中出现一次;第二个称之为该关键字的对应值。一. 声明//头文件 #include<map>map<int, string> ID_Name;...
  • shuzfan
  • shuzfan
  • 2016-11-10 15:07
  • 24484

C++学习 std::map介绍

给出了map的基本用法如插入、查找、删除、遍历等等,同时告诉你如何实现双键map,包括  (1) 只有两个键都匹配才命中目标 (2) 两个键中任意一个匹配就命中目标 可以扩展到多键 (一) 介绍 特点: 1.map将Key的object和T的Object绑定到一起,因此...
  • skdkjxy
  • skdkjxy
  • 2015-02-03 20:16
  • 3131

C++中std::map的使用

C++中std::map的使用
  • fengbingchun
  • fengbingchun
  • 2016-07-30 18:38
  • 2547

std::map用法

std::map用法    STL是标准C++系统的一组模板类,使用STL模板类最大的好处就是在各种C++编译器上都通用。    在STL模板类中,用于线性数据存储管理的类主要有vector, list, map 等等。本文主要针对map对象,...
  • TXH0001
  • TXH0001
  • 2011-03-12 13:40
  • 75033

C++11中std::unordered_map的使用

C++11中std::unordered_map的使用
  • fengbingchun
  • fengbingchun
  • 2016-08-17 21:55
  • 9490

【C++】STL常用容器总结之八:映射map

9、映射mapMap是键-值对的集合,map中的所有元素都是pair,可以使用键作为下标来获取一个值。Map中所有元素都会根据元素的值自动被排序,同时拥有实值value和键值key,pair的第一元素被视为键值,第二元素被视为实值,同时map不允许两个元素有相同的键值。要使用map对象,必须包含ma...
  • hero_myself
  • hero_myself
  • 2016-08-25 12:20
  • 1621

慎用C++ std::map 的[]运算符

map的[]运算符在用法上和我们对[]常规理解大有出入,因此也往往很容易造成了使用上的失误,在这点上我强烈认为stl设计犯了大错。首先看其函数声明:T& operator[] ( const key_type& x );在 http://www.cplusplus.com/refer...
  • roofalison
  • roofalison
  • 2008-09-18 13:48
  • 7020

std::map容器序列化、反序列化测试

// testSerialize.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include #include #include #include...
  • lee353086
  • lee353086
  • 2014-09-16 09:15
  • 3225

STL中map的简单应用(合并表序列)

描述 数据表记录包含表索引和数值。请对表索引相同的记录进行合并,合并后表记录为相同索引表的数值求和 函数说明:public int mergeRecord(List oriList, List rstList)数据表记录包含表索引和数...
  • huangfei711
  • huangfei711
  • 2015-08-06 10:52
  • 2018
    个人资料
    • 访问:383039次
    • 积分:4198
    • 等级:
    • 排名:第8668名
    • 原创:92篇
    • 转载:5篇
    • 译文:1篇
    • 评论:61条
    博客专栏
    我的开源项目
    最新评论