C++容器(四):map类型
2015-10-01 21:46
381 查看
map 类型
map是键-值对的集合。
map类型通常可以理解为关联数组:可以使用键作为下标来获取一个值,正如内置数组类型一样。而关联的本质在于元素的值与某个特定的键相关联,而非通过元素在数组内的位置来获取。
要使用
map对象,必须包含
map头文件:
[code]#include <map>
在定义
map对象时,必须指明键和值的类型:
[code]map<string, int> wordCount; // empty map from string to int
1 map
对象的构造函数
操作 | 含义 |
---|---|
map<k, v> m | 创建一个名为m的 map对象,其键和值的类型分别为 k和 v |
map<k, v> m(m2) | 创建m2的副本 m, m与 m2必须具有相同的键类型和值类型 |
map<k, v> m(b, e) | 创建map类型的对象 m,存储迭代器 b和 e标记范围内的所有元素副本。元素的类型必须能够转换为 pair<const k, v> |
<操作,至于是否支持其他关系或相等运算,则不做要求。
2 map
定义的类型
包括:键类型,值类型以及键-值(pair)类型。
类型 | 含义 |
---|---|
map<k, v>::key_type | 在map容器中,用作索引的键的类型 |
map<k, v>::mapped_type | 在map类型中,键所关联的值的类型 |
map<k, v>::value_type | 一个pair类型,它的 first元素具有 const map<k, v>::key_type类型,而 second则为 map<k, v>::mapped_type类型 |
map迭代器进行解引用将产生
pair类型的对象
对迭代器进行解引用时,将获得一个引用,指向容器的一个
value_type类型值。
[code]map<string, int>::iterator map_it = wordCount.begin(); // *map_it is a reference to a pair<const string, int> object cout << map_it->first << " " << map_it->second << endl; // print the key and value of the element map_it->first = "new key"; // error: key is const type ++ map_it->second; // ok: we can change value through the iterator
3 给map
添加元素
给map中添加键-值元素对时,有两种方式:一种是先用下标操作符获取元素,然后给获取的元素赋值,一种是使用
insert成员函数实现。
[b]3.1 使用下标访问
map对象[/b]
如编写下段程序时:
[code]map<string, int> wordCount; // empty map // insert default initialized element with key "Anna"; then assign 1 to its value wordCount["Anna"] = 1;
将发生以下事情:
在wordCount中查找键为
Anna的元素,没有找到;
将一个新的键-值对插入到
wordCount中。它的键是
const string类型的对象,保存
Anna。而它的值则采用值初始化,这就意味着在本例中值为0;
将这个新的键-值对插入到
wordCount中;
读取插入的新元素,并将它的值赋为1。
下标操作符返回值的使用
通常来说,下标操作符返回左值。它返回的左值是特定键所关联的值。
[code]cout << wordCount["Anna"] <<endl; // fetch element indexed by Anna; ptint 1 ++ wordCount["Anna"]; // fetch the element and add one to it cout << wordCount["Anna"] << endl; // fetch element and print it; print 2
有别于
vector或
string类型,
map下标操作符返回的类型与对
map迭代器进行解引用获得的类型不相同。
下标行为的编程意义
对于
map容器,如果下标表示的键在容器中不存在,则添加新元素,这一特性可使程序惊人的简练:
[code]// count the number of times each word occurs in the input map<string, int> wordCount; // empty map from string to int string word; while ( cin >> word ) ++ wordCount[word];
这段程序创建一个
map对象,用来记录每个单词出现的次数,
while循环每次从标准输入读取一个单词,如果这是一个新的单词,则在
wordCount中添加以该单词为索引的新元素,如果读入单词已经在
map对象中,则将它所对应的值加1。
[b]3.2
insert成员函数[/b]
map容器的
insert成员与顺序容器的类似,但有一点要注意:必须考虑键的作用。
操作 | 含义 |
---|---|
m.insert(e) | e是一个用在 m上的 value_type类型的值。如果键( e.first)不在 m中,则插入一个值为 e.second的新元素;如果键在 m中已经存在,则保持 m不变。该函数返回一个 pair类型对象,包含指向键为 e.first的元素的 map迭代器,以及一个 bool的对象,表示是否插入了该元素 |
m.insert(begin, end) | begin和 end是标记元素范围的迭代器,其中的元素必须为 m.value_type类型的键-值对。对于该范围内的所有元素,如果其键在 m中不存在,则将该键及其关联的值插入 m。返回 void类型 |
m.insert(iter, e) | e是一个用在 m上的 value_type类型的值。如果键( e.first)不在 m中,则创建新元素,并以迭代器 iter为起点搜索新元素存储的位置。返回一个迭代器,指向 m中具有给定键的元素 |
insert代替下标运算
使用下标给
map容器添加新元素时,元素的值部分将采用值初始化。通常,我们会立即为其赋值,其实就是对同一个对象进行初始化并赋值。而
insert其语法更加紧凑:
[code]// if Anna not already in wordCount, inserts new element with value 1 wordCount.insert( map<string, int>::value_type("Anna", 1) );
这个
insert函数版本的实参:
[code]map<string, int>::value_type("Anna", 1)
是一个新创建的
pair对象,将直接插入到
map容器中。但是传递给
insert的实参相当笨拙,有两种方法可以简化:
[code]// first wordCount.insert( make_pair("Anna", 1) ); // second typedef map<string, int>::value_type valueType; wordCount.insert( valueType("Anna", 1) );
前面我们已经学会了,使用下标操作符统计输入的单词,
insert成员函数同样可以实现:
[code]// count number of times each word occurs in the input map<string, int> wordCount; // empty map from string to int string word; while ( cin >> word ) { // insert element with key equal to word and value 1 // if word already in wordCount, insert does nothing pair<map<string, int>::iterator, bool> ret = wordCount.insert(make_pair(word, 1)); if ( !ret->second ) // word already in wordCount ++ ret.first->second; // increment counter }
本处使用了带有一个键-值
pair形参的
insert版本将返回:包含一个迭代器和一个
bool值的
pair对象,其中迭代器指向
map中具有相应键的元素,而
bool值则表示是否插入了该元素。如果该键已在容器中,则其关联的值保持不变,返回的
bool值为
false;如果该键不在容器中,则插入新元素,且
bool值为
true。对于每个单词,都尝试
insert它,并将它的值赋为1。
if语句检测
insert函数返回值,如果值为
false则表示没有做插入操作;按照
word索引的元素已在
wordCount中存在,此时将该元素所关联的值加1。
4 查找并读取map
元素
下标操作符给出了读取一个值的最简单方法:[code]map<string, int> wordCount; // empty map from string to int int occurs = wordCount["Anna"];
但是,该方法存在一个副作用:如果该键不存在
map容器中,则下标操作会插入一个具有该键的新的元素。大多数情况下,我们其实只是想知道某元素是否存在,当该元素不存在时,我们并不打算进行插入运算。为此,
map容器提供的两个操作可以解决这一问题。
操作 | 含义 |
---|---|
m.count(k) | 返回m中 k的出现次数 |
m.find(k) | 如果m容器中存在按 k索引的元素,则返回指向该元素的迭代器。如果不存在,则返回指向超出末端迭代器 |
[code]// count() int occurs(0); if ( wordCount.count("Anna") ) occurs = wordCount["Anna"]; // find() int occurs(0); map<string, int>::iterator iter = wordCount.find("Anna"); if ( iter != wordCount.end() ) occurs = iter->second;
5 从map
对象中删除元素
操作 | 含义 |
---|---|
m.erase(k) | 删除m中键为 k的元素。返回 size_type类型的值,表示删除的元素的个数 |
m.erase(p) | 从m中删除迭代器 p所指向的元素。 p必须指向 m中确实存在的元素,而且不能等于 m.end()。返回 void类型 |
m.erase(b, e) | 从m中删除一段范围内的元素,该范围由迭代器对 b和 e标记。 b和 e必须标记 m中的一段有效范围:即 b和 e都要指向 m中的元素或最后一个元素的下一个位置。并且, b和 e要么相等(此时删除范围为空),要么 b所指向的元素必须出现在 e所指向的元素之前。返回 void类型 |
[code]// erase of a key returns number of elements removed if ( wordCount.erase( removalWord ) ) cout << "ok: " << removalWord << " removed!" << endl; else cout << "oops: " << removalWord << " not found!" << endl;
6 对map
对象的迭代遍历
[code]// get iterator positioned on the first element map<string, int>::const_iterator iter = wordCount.begin(); // for each element in the map while ( iter != wordCount.end() ) { // print the element key, value pairs cout << iter->first << " occurs " << iter->second << " times." << endl; ++ iter; // increment iterator to denote the next element }
参考文献:
《C++ Primer中文版(第四版)》,Stanley B.Lippman et al. 著, 人民邮电出版社,2013。
相关文章推荐
- C/C++语言基础面试相关
- c++简单工厂模式
- C++容器(二):关联容器简介
- C++容器(二):关联容器简介
- leetcode 242 :Valid Anagram
- 位操作基础篇之位操作全面总结
- #LeetCode# #C++# Symmetric Tree
- EffectiveC++
- 从C++strStr到字符串匹配算法
- c和c++易错点拾露
- C语言之进制、位运算符、数组
- 读取数量不定的输入数据
- c++primer读书笔记零(开读篇)
- C语言及程序设计.第二十三课.项目6.前导0的数字
- c++ 读写Excel及数据导入SQLServer
- C语言及程序设计.第二十三课.项目5.我的加班费
- 单链表顺序存储相关操作的c语言实现
- C++ 多重继承和虚继承的内存布局
- C++ | 数组与指针
- 2013级别C++文章9周(春天的)工程——运算符重载(两)