C++中STL标准容器类映射MAP简单入门使用详解,MAP容器类简单相关实例

之前几篇文章讨论的C++语言中的 STL 模板容器类存放的都是单一类型的数据:

本文将介绍C++语言中的 STL 模板容器类:map(映射),它是一个关联容器类,内部存放的是 key-value 键值对,其中的“key(键)”总是独一无二的,可以从容器中删除它,也可以把新的key-value插入到容器中,但是一旦插入,key 本身就无法修改了,其对应的 value 倒是可以修改,下面将通过实例看到这一点。

声明和初始化

C++语言程序开发中,要使用 map 容器,需要包含<map>头文件:

#include <map>

map 容器中的 key-value 的数据类型可以是任意的,定义一个 map 对象的C++语言代码可以如下写:

std::map<key_type, value_type> val;

map在标准命名空间std中,下文为了方便,实例代码不再写std::

其中的 key_typevalue_type 分别表示 key-value 中的 key 的数据类型和 value 的数据类型,例如:

map <int, int> mymap;

这表示 map 对象 mymap 容器中存放的将是 int-int 类型的数据,在C++11标准的支持下,可以在定义 map 对象的同时赋初值,例如:

map<int, int> mymap {{1, 10}, {2, 20}, {3, 30}};

上面这行C++语言代码执行后,mymap 容器中将有 3 个键值对。应该注意,在往 map 容器中插入元素时,必须以 key-value 的形式,而不能只插入 key 或者只插入 value。

操作 map

C++语言中的 map 容器类的基本操作同前面介绍的几个容器类大体相同,常用的包括以下几个操作(或者说成员函数):

  • at 和 []:用于访问 map 容器中的元素,at 和 [] 的功能基本相同,只有一个区别:如果访问 map 容器中不存在的元素,at 将抛出一个异常,而 [] 操作符则将这个“不存在的元素”插入到 map 容器中。
  • begin:返回 map 容器中第一个元素的迭代器指针。
  • end:返回 map 容器末尾位置(最后一个元素的下一个位置)的迭代器指针。

下面是一段C++语言代码示例,该示例主要使用了前文提到的点,请看:

#include <iostream>
#include <map>

using namespace std;

int main()
{
    map<int, int> mymap {{1,10},{2,20},{3,30}};
    // 遍历 mymap
    map<int,int> :: iterator it;
    cout << "\nThe map mymap is : \n";
    cout << "\tKEY\tVALUE\n";
    for (it = mymap.begin(); it != mymap.end(); ++it) {
        cout << '\t' << it->first
        << '\t' << it->second << '\n';
    }
    cout << endl;

    mymap.at(2) = 10;   // 修改 key(2) 对应的值
    mymap[3] = 10;      // 修改 key(3) 对应的值
    //遍历修改后的 mymap
    cout << "\nThe map mymap is : \n";
    cout << "\tKEY\tVALUE\n";
    for (it = mymap.begin(); it != mymap.end(); ++it) {
        cout << '\t' << it->first
        << '\t' << it->second << '\n';
    }
    cout << endl;

    return 0;
}

上面这段C++语言代码很简单:先定义了一个 map 对象 mymap,并且初始化了 3 个键值对,然后将之打印出来。在打印过程中可以看出,迭代器指针的 first 成员对应着 key,而 second 成员则对应着 value。之后,通过 at 和 [] 操作符分别将 key(2) 和 key(3) 对应的值修改为 10,再打印出修改后的 mymap。编译这段C++语言代码时注意指定-std=c++11,输出如下:

# g++ t1.cpp -std=c++11
# ./a.out 

The map mymap is : 
    KEY VALUE
    1   10
    2   20
    3   30

The map mymap is : 
    KEY VALUE
    1   10
    2   10

一切与预期一致。当然了,map 容器类比较常用的操作方法还有一些:

  • insert(key, value):将键值对(key, value)插入到 map 容器中。
  • erase:从 map 容器中删除元素,该方法有两个版本:

    • erase(pos) - 删除 map 容器中指定位置 pos 处的元素。
    • erase(key) - 删除 key 对应的元素。
  • empty:检查 map 容器是否没有元素。
  • size:返回 map 容器中元素的数目。
  • max_size:返回 map 容器能够容纳的最多元素数目。
  • clear:删除 map 容器中的所有元素。
  • count:返回容器中给定 key 对应的元素数目。

下面是一段C++语言代码示例,请看:

#include <iostream>
#include <map>
using namespace std;
int main()
{
   map<int,int> mymap;
   mymap.insert(pair<int, int>(1, 1));
   mymap.insert(pair<int, int>(2, 3));
   mymap.insert(pair<int, int>(3, 5));
   mymap.insert(pair<int, int>(4, 7));
   mymap.insert(pair<int, int>(5, 9));
   mymap.insert(pair<int, int>(6, 11));
   mymap.insert(pair<int, int>(7, 13));

   map<int,int> :: iterator it;
   cout << "\nThe map mymap is : \n";
   cout << "\tKEY\tVALUE\n";
   for (it = mymap.begin(); it != mymap.end(); ++it) {
      cout << '\t' << it->first
      << '\t' << it->second << '\n';
      }
   cout << endl;
   cout<<"\n mymap.size(): "<<mymap.size();
   cout<<"\n mymap.max_size(): "<<mymap.max_size();
   cout<<endl;
   int num;
   num = mymap.erase(3);
   cout << "\nmymap.erase(3) : ";
   cout << num << " removed \n";
   cout << "\tKEY\tELEMENT\n";
   for (it = mymap.begin(); it != mymap.end(); ++it) {
      cout << '\t' << it->first
      << '\t' << it->second << '\n';
      }
   cout << endl;
   mymap.clear();
   cout<<"\nAfter clear operation mymap.size() : "<<mymap.size() <<endl;

   return 0;
}

上面的C++语言代码首先使用 insert() 函数插入了 7 组键值对,并且打印了它们,接着通过 size() 和 max_size() 函数分别输出了当前容器 mymap 中的元素数目,和能够容纳的最多数目(这主要取决于机器内存)。

接着,代码调用了 erase(3) 函数删除了 key(3) 对应的元素,并打印了出来。最后代码调用了 clear() 函数删除了容器中所有的元素,此时 size() 函数将返回 0。

同样的,编译这段C++语言代码需要指定-std=c++11选项,最终输出如下,请看:

# g++ t2.cpp -std=c++11
# ./a.out 

The map mymap is : 
    KEY VALUE
    1   1
    2   3
    3   5
    4   7
    5   9
    6   11
    7   13

 mymap.size(): 7
 mymap.max_size(): 461168601842738790

mymap.erase(3) : 1 removed 
    KEY ELEMENT
    1   1
    2   3
    4   7
    5   9
    6   11
    7   13
After clear operation mymap.size() : 0

多重映射 multimap

multimap 和 map 在绝大多数方面都是相似的,比较明显的区别是 multimap 允许多个元素拥有相同的 key,所以,multimap 中的元素的 key 可以不是独一无二的,不过这样一来,就不能再通过 at 和 [] 方法访问元素了。

操作 multimap 容器类的方法与操作 map 容器类的方法大体相同,下面是一段C++代码示例:

#include <iostream>
#include <map>

using namespace std;

int main()
{
   multimap<int,int> mymap;
   mymap.insert(pair<int, int>(1, 1));
   mymap.insert(pair<int, int>(2, 3));
   mymap.insert(pair<int, int>(3, 5));
   mymap.insert(pair<int, int>(3, 7));
   mymap.insert(pair<int, int>(4, 9));

   map<int,int> :: iterator it;
   cout << "\nThe multimap mymap is : \n";
   cout << "\tKEY\tVALUE\n";
   for (it = mymap.begin(); it != mymap.end(); ++it) {
      cout << '\t' << it->first
      << '\t' << it->second << '\n';
      }
   cout << endl;
   cout<<"\n mymap.size(): "<<mymap.size();
   cout<<"\n mymap.max_size(): "<<mymap.max_size();
   cout<<endl;
   int num;
   num = mymap.erase(3);
   cout << "\nmymap.erase(3) : ";
   cout << num << " removed \n";
   cout << "\tKEY\tELEMENT\n";
   for (it = mymap.begin(); it != mymap.end(); ++it) {
      cout << '\t' << it->first
      << '\t' << it->second << '\n';
     }
   cout << endl;
   mymap.clear();
   cout<<"\nAfter clear operation mymap.size() : "<<mymap.size();

   return 0;
}

这段C++语言代码与前面操作 map 容器类的代码几乎相同,编译这段代码并执行,得到如下输出:

# g++ t3.cpp -std=c++11
# ./a.out 

The multimap mymap is : 
    KEY VALUE
    1   1
    2   3
    3   5
    3   7
    4   9

 mymap.size(): 5
 mymap.max_size(): 461168601842738790

mymap.erase(3) : 2 removed 
    KEY ELEMENT
    1   1
    2   3
    4   9

After clear operation mymap.size() : 0

我们将注意力放在 key(3) 上,从输出来看,multimap 容器类的确允许同一个 key 被多个元素使用,但是也要注意,因为不能保证唯一性,multimap 容器类没有 at 和 [] 方法。

无序映射 unordered_map

和普通的 map 一样,C++语言中的 unordered_map 类也是一种存储 key-value 对的容器。只不过,unordered_map 中的元素可以是无序的。

与普通的 map 一样,unordered_map 容器中的 key 也是用于映射 value 的,相关的 key-value 类型也可以是任意的。

unordered_map 容器类内部的无序映射的实现是由“哈希表”数据结构提供的,key 对应着哈希表中的索引,因此,unordered_map 容器类的性能在很大程度上取决于所提供的哈希函数。

使用 unordered_map 容器类需要包含头文件 <unordered_map>,实例化一个对象和普通 map 没有什么区别:

#include <unordered_map>
std::unordered_map<key_type, value_type> val;

因为 unordered_map 容器内部使用的是哈希表数据结构,所以相比于普通 map 容器类多出了几个方法:

  • bucket:返回容器中 key 对应元素的 bucket 数目。
  • bucket_count:返回容器中所有的 bucket 数目。
  • bucket_size:返回每个 bucket 中的元素数目。

关于 bucket,之后的文章会讨论。

下面是一段C++语言代码示例,请看:

#include <iostream> 
#include <unordered_map> 

using namespace std; 

int main() 
{     
    unordered_map<string, int> umap; 

    // 使用 [] 操作符插入元素
    umap["RED"] = 1; 
    umap["GREEN"] = 2; 
    umap["BLUE"] = 3; 

    // 使用 insert() 函数插入元素
    umap.insert(make_pair("YELLOW", 4)); 

    unordered_map<string, int>:: iterator it; 
    cout << "\nAll Elements in unordered map umap : \n"; 
    for (it = umap.begin(); it != umap.end(); ++it) 
    { 

        cout << it->first << "\t" << it->second << endl; 
    } 
    cout<<endl;
    cout<<"bucket of RED: "<<umap.bucket("RED") <<endl;
    cout<<"umap bucket_count : "<<umap.bucket_count()<<endl;
    cout<<"size of first bucket: "<<umap.bucket_size(1)<<endl;

    return 0;
}

上述C++语言代码的前半段和操作普通的 map 容器类没什么区别,后半段主要打印了几个 bucket 相关的值。编译这段代码并执行,得到如下输出:

# g++ t4.cpp -std=c++11
# ./a.out 

All Elements in unordered map umap : 
YELLOW  4
BLUE    3
GREEN   2
RED 1

bucket of RED: 1
umap bucket_count : 11
size of first bucket: 1

小结

本文主要讨论了C++语言中的标准容器类map及其相关的两个变种类multimapunordered_map的基本使用,其内部实现倒是浅尝辄止了。不过,学会使用它们对理解它们是有所帮助的,熟练后再去理解相关的详细设计和实现,绝对是事半功倍的。

阅读更多:   C++
添加新评论

icon_redface.gificon_idea.gificon_cool.gif2016kuk.gificon_mrgreen.gif2016shuai.gif2016tp.gif2016db.gif2016ch.gificon_razz.gif2016zj.gificon_sad.gificon_cry.gif2016zhh.gificon_question.gif2016jk.gif2016bs.gificon_lol.gif2016qiao.gificon_surprised.gif2016fendou.gif2016ll.gif