c++映射map、multimap详解

c++映射map、multimap详解

3 个月前 · 来自专栏 c++STL基础及应用相关问题研究

首先map 容器存储的都是 pair 对象,也就是用 pair 类模板创建的键值对。其中,各个键值对的键和值可以是任意数据类型,包括 C++ 基本数据类型(int、double 等)、使用结构体或类自定义的类型。

其次在使用 map 容器存储多个键值对时,该容器会自动根据各键值对的键的大小,按照既定的规则进行排序。

默认情况下,其会根据键的大小对所有键值对做升序排序,即使用std::less<Key>;根据实际情况的需要,既可以选用 STL 标准库中提供的其它排序规则(比如std::greater<Key>),也可以自定义排序规则(在value为类时使用)。

需要注意的是,使用 map 容器存储的各个键值对,键的值既不能重复也不能被修改。换句话说,map 容器中存储的各个键值对不仅键的值独一无二, 键的类型也会用 const 修饰 ,这意味着只要键值对被存储到 map 容器中,其键的值将不能再做任何修改。

map 容器定义

#include <map>
using namespace std;

map 容器的模板定义如下:

template < class Key,                                     // 指定键(key)的类型
           class T,                                       // 指定值(value)的类型
           class Compare = less<Key>,                     // 指定排序规则
           class Alloc = allocator<pair<const Key,T> >    // 指定分配器对象的类型
           > class map;

构造函数:

  • map(const Pred& comp=Pred(),const A& al=A()):创建空映射。
  • map(const map& x):复制构造函数。
  • map(const value_type * first,const value_type * last,const Pred& comp=Pred(),const A& al=A()):复制[first,last)之间元素构成新映射。
  • multimap(const Pred& comp=Pred(),const A& al=A()):创建空映射。
  • multimap(const multimap& x):复制构造函数。
  • multimap(const value_type * first,const value_type * last,const Pred& comp=Pred(),const A& al=A()):复制[first, last)之间元素构成新映射。
#include <iostream>
#include <string>
#include <map>
using namespace std;
void Display(map<int, string>& m) {
    map<int, string>::iterator te = m.begin();
    while (te != m.end()) {
        cout << (*te).first << "\t" << te->second << endl;
        te++;
int main() {
    map<int, string>mymap;
    pair<int, string>s1(1, "zhangsan");
    pair<int, string>s2(3, "lisi");
    pair<int, string>s3(6, "wangwu");
    pair<int, string>s4(5, "zhaoliu");
    pair<int, string>s5(1, "zhangsan");
    mymap.insert(s1);
    mymap.insert(s2);
    mymap.insert(s3);
    mymap.insert(s4);
    auto res = mymap.insert(s5);
    cout<< typeid(res).name() <<endl;
    if(!res.second){
        cerr<< "Fail to insert a pair<K,V>" <<endl;
    cout << "通过insert构建map: " << endl;
    Display(mymap);
    cout << "通过复制构造函数构建map: " << endl;
    map<int, string>mymap2(mymap);
    Display(mymap2);
    return 0;
}

map不允许有重复键值,本例中有5个pair 对象,且 sl、s5有相同的键值,则在map 容器中只保留先存入的s1对象, s5则不能保存。如果把map换成multimap,则可以保存s5了。


特殊函数:

reference operator[](const Key& k):仅用在单映射map类中,可以以数组的形式给映射添加键值对,并可返回值的引用。

#include <iostream>
#include <string>
#include <map>
using namespace std;
int main() {
        map<string, string>mymap;
        mymap["1-1"] = "元旦";
        mymap["5-1"] = "五一劳动节";
        mymap["7-1"] = "建党节";
        mymap["8-1"] = "建军节";
        mymap["10-1"] = "国庆节";
        //mymap["6-1"] = "";
        string s = mymap["1-1"];
        if (s.length() > 0) {
               cout << "1-1 is: " << s << endl;
        else {
               cout << "1-1 not resident" << endl;
        try {
               string s2 = mymap.at("6-1");
               cout << s2 << endl;
        catch (const out_of_range& e) {
               cerr << e.what() << "\t" << "6-1" << "not find." << endl;
        if (mymap.count("6-1")) {
               cout << mymap["6-1"] << endl;
        else {
               cout << "6-1" << "not found." << endl;
        string s1 = mymap["6-1"];
        if (s1.length() > 0) {
               cout << "6-1 is: " << s1 << endl;
        else {
               cout << "6-1 not resident" << endl;
        return 0;
}

增加、删除函数:

  • iterator insert(const value_type&. x):插人元素x。
  • iterator insert(iterator it,const value_type& x):在迭代指针it处插入元素x。
  • void insert(const value_type * first,const value_type * last):插入[first, last)间元素。
  • iterator erase(iterator it):删除迭代指针it处元素。
  • iterator erase(iterator first,iterator last):删除[first,last)迭代指针间元素。
  • size_type erase(const Key& key):删除键值等于key的元素。


遍历函数:

  • iterator begin():返回首元素的迭代器指针。
  • iterator end():返回尾元素后的迭代器指针,而不是尾元素的迭代器指针。re
  • verse_iterator rbegin():返回尾元素的逆向迭代器指针,用于逆向遍历容器。reverse_iterator
  • rend():返回首元素前的逆向迭代器指针,用于逆向遍历容器。

假设公司雇员属性有雇员姓名(没有重复的姓名)部门名称。编制管理雇员的集合类,仅包含:(1)添加雇员功能;(2)显示功能,要求按部门名称升序排列,若部门名相同,则按姓名升序排列。

#include <iostream>
#include <string>
#include <set>
using namespace std;
class CEMployee
public:
        CEMployee(string name, string departname){
               this->name = name;
               this->departname = dapartname;
        bool operator<(const CEMployee& e)const {
               bool mark = (departname.compare(e.departname) < 0) ? true : false;
               if (departname.compare(e.departname) == 0) {
                       mark = (name.compare(e.name) < 0) ? true : false;
               return mark;
        string GetName()const { return name; }
        string GetDepart()const { return departname; }
private:
        string name;
        string departname;
class CManage {
        multiset<CEMployee>myset;
public:
        bool Add(CEMployee& e) {
               myset.insert(e);
               return true;
        void show() {
               multiset<CEMployee>::iterator te = myset.begin();
               while (te != myset.end()) {
                       const CEMployee& obj = *te;           //以引用的方式指向本身ref
                       cout << obj.GetName() << "\t" << obj.GetDepart() << endl;
                       te++;
int main() {
        CEMployee e1("Jon", "人力部");
        CEMployee e2("LiSa", "装配部");
        CEMployee e3("BaTa", "制造部");
        CEMployee e4("LiNa", "制造部");
        CEMployee e5("Mack", "装配部");
        CEMployee e6("Anna", "制造部");
        CManage manage;
        manage.Add(e1);
        manage.Add(e2);
        manage.Add(e3);
        manage.Add(e4);
        manage.Add(e5);
        manage.Add(e6);
        manage.show();
        return 0;
}

由于一个部门可以有许多雇员﹐因此应当采用multiset类。应该利用集合类,在添加雇员时,直接完成先按部门升序排列,再按姓名升序排列,即在恰当的位置重载operator≤运算符,完成自定义排序规则功能。


如何获得有关multimap对象的信息呢?成员函数count()接受键作为参数,并返回具有该键的元素数目。成员函数 lower_bound()和 upper_bound()将键作为参数。成员函数equal_range()用键作为参数,且返回两个迭代器,它们表示的区间与该键匹配。为返回两个值,该方法将它们封装在一个pair对象中,这里pair 的两个模板参数都是迭代器。

操作函数:

  • const_iterator lower_bound(const Key& key):返回键值大于等于key的迭代指针,否则返回end()。
  • const_iterator upper_bound(const Key& key):返回键值大于 key的迭代指针,否则返回end()。
  • int count(const Key&. key) const:返回容器中键值等于key的元素个数。
  • pair≤const_iterator,const_iterator> equal_range(const Key& key) const:返回容器中键值等于key的迭代指针[first,last)。
  • const_iterator find(const Key& key) const:查找功能,返回键值等于key的迭代器指针。
  • void swap(map& s):交换单映射元素。
  • void swap(multimap&. s):交换多映射元素。


例如,下面的代码打印 codes对象中区号为718的所有城市:

#include <iostream>
#include <string>
#include <map>
#include <algorithm>
typedef std::pair<const int, std::string> Pair;
typedef std::multimap<int, std::string> MapCode;
int main(){
    using namespace std;
    MapCode codes;
    codes.insert(Pair(415, "北京"));
    codes.insert(Pair(510, "大连"));
    codes.insert(Pair(718, "太原"));
    codes.insert(Pair(718, "拉萨"));
    codes.insert(Pair(415, "上海"));
    codes.insert(Pair(510, "广州"));
    cout<< "Number of cities with area code 415: "
        << codes.count(415) <<endl;
    cout<< "Number of cities with area code 718: "
        << codes.count(718) <<endl;
    cout<< "Number of cities with area code 510: "
        << codes.count(510) <<endl;
    pair<MapCode::iterator, MapCode::iterator> range
        = codes.equal_range(718);
    cout<< "Cities with area code 718: " <<endl;
    for(auto it = range.first; it != range.second; it++){
        cout<< (*it).second <<endl;
    return 0;
}

编一个同义词字典功能类,每个单词后面跟着它的同义词

#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;
class CWord {
private:
        string mainword;
        vector<string>vecword;
public:
        CWord(string strLine) {
               istringstream in(strLine);
               in >> mainword;
               string mid = "";
               while (!in.eof()) {
                       in >> mid;
                       vecword.push_back(mid);
        string GetMainWord() { return mainword; }
        void Show() {
               cout << endl;
               cout << "单词是: " << "\t" << mainword << endl;
               cout << "同义词是: " << "\t";
               for_each(vecword.begin(), vecword.end(), [](string s) {
                       cout << s << "\t";
               cout << endl;
class CWordManage {
        multimap<string, CWord>mymap;
public:
        bool Add(string strLine) {
               CWord word(strLine);
               pair<string, CWord>p(word.GetMainWord(), word);
               mymap.insert(p);
               return true;
        void Show_Find(string strFind) {
               multimap<string, CWord>::iterator itfind = mymap.find(strFind);
               if (itfind != mymap.end()) {
                       CWord& obj = (*itfind).second;
                       obj.Show();
               else {
                       cout << strFind << "字典里没有记录同义词" << endl;
        void Show() {
               multimap<string, CWord>::iterator te = mymap.begin();
               while (te != mymap.end()) {
                       CWord& obj = (*te).second;
                       obj.Show();
                       te++;
int main() {
        string s[5]{ string("one single unique"), string("correct true right"),
                              string("near close"), string("happy please"),
                              string("strong powerful") };
        CWordManage manage;
        for (int i = 0; i < 5; i++) {
               manage.Add(s[i]);
        manage.Show();