C++ primer【笔记】关联容器 map

1.pair对象

pair对象类型在 utility 头文件中定义。

表1.1 pair 类型提供的操作

pair< T1, T2 > p1;创建一个空的 pair 对象,它的两个元素分别是 T1 和 T2类型,采用值初始化
pair< T1, T2 > p1(v1,v2);创建一个 pair 对象,它的两个元素分别是 T1 和 T2 ,其中 first 成员初始化为 v1,而 second 成员初始化为 v2
make_pair(v1,v2);以 v1 和 v2 值创建一个新 pair 对象,其元素类型分别是v1 和 v2 的类型
p1 < p2两个 pair 对象之间的小于运算,其定义遵循字典次序:如果 p1.first < p2.first 或者 !(p2.first < p1.first) &&p1.second < p2.second,则返回 true
p1 == p2如果两个 pair 对象的 first 和 second 成员依次相等,则这两个对象相等。该运算使用其元素的 == 操作符
p.first返回 p 中名为 first 的(公有)数据成员
p.second返回 p 的名为 second 的(公有)数据成员

*
对于 pair 类,可以直接访问其数据成员:其成员都是仅有的,分别命名为 first 和 second。只需使用普通的点操作符——成员访问标志即可访问其成员

vector容器中的pair对象输出问题:
《c++ primer》习题 exercise 10.1的程序如下:
Exercise 10.1 编写程序读入一系列 string 和 int 型数据, 将每一组存储在一个 pair 对象中,然后将这些 pair 对象存储在 vector 容器里。

#include<iostream>
#include<vector>
#include<utility>
#include<string>
using namespace std;
int main(){
    pair<string, int> p;
    vector< pair<string, int> > vps;
    string s;
    int i;
    while(cin >> s >> i){
        p = make_pair(s, i);
        vps.push_back(p);
    }

    for(vector< pair<string, int> >::iterator iter = vps.begin(); iter != vps.end(); ++iter)
        cout << iter->first << " "  << (*iter).second << endl;
//  for(vector<string>::iterator iter = vs.begin(); iter != vs.end(); ++iter)
//      cout << *iter << endl;
    return 0;
}

访问成员操作符"."优先级高于解引用操作符"*",所以(*iter).second要加括号, 因为 iter 是指向 pair 对象的,所以同时可以使用iter->first访问pair 对象。

2.map对象

使用map对象必须包含map头文件,必须指明键和值得类型。
map< string, int > word_count;
表2.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

*
表2.2 map类定义的类型

map< K,V >::key_type在 map 容器中,用做索引的键的类型
map< K, V >::mapped_type在 map 容器中,键所关联的值的类型
map< K, V >::value_type一个 pair 类型,它的 first 元素具有const map::key_type 类型,而 second 元素则为 map::mapped_type 类型

*
在学习 map 的接口时,需谨记 value_type 是 pair 类型,它的值成员可以修改,但键成员不能修改。对迭代器进行解引用时,将获得一个引用,指向容器中一个 value_type 类型的值。对于 map 容器,其 value_type 是 pair 类型,它的 first 成员存放键,为const,而 second 成员则存放值。
给map容器添加元素,可使用 insert 成员实现;或者,先用下标操作符获取元素,然后给获取的元素赋值。
使用下标访问map:

map< string, int > word_count;
word_count["WB"] = 1;

将发生以下事情:

  1. 在 word_count 中查找键为 WB 的元素,没有找到。

  2. 将一个新的键-值对插入到 word_count 中。它的键是 const string 类型的对象, 保存 WB。 而它的值则采用值初始化, 这就意味着在本例中值为 0。

  3. 将这个新的键-值对插入到 word_count 中。

  4. 读取新插入的元素,并将它的值赋为 1。

使用下标访问 map 与使用下标访问数组或 vector 的行为截然不同:用下标访问不存在的元素将导致在 map 容器中添加一个新元素,它的键即为该下标值。

有别于 vector 或 string 类型,map 下标操作符返回的类型与对 map 迭代器进行解引用获得的类型不相同。显然,map 迭代器返回 value_type 类型的值——包含 const key_type 和apped_type 类型成员的 pair 对象;下标操作符则返回一个 mapped_type 类型的值。

map< string, int > word_count;
while (cin >> word)
    ++word_count[word];

这段程序创建一个 map 对象,用来记录每个单词出现的次数。while 循环每次从标准输入读取一个单词。如果这是一个新的单词,则在 word_count 中添加以该单词为索引的新元素。如果读入的单词已在 map 对象中,则将它所对应的值加 1。

表2.3 map 提供的 insert 操作

m.insert(e)e 是一个用在 m 上的 value_type 类型的值。如果键(e.first)不在 m 中,则插入一个值为 e.second 的新元素;如果该键在 m 中已存在,则保持 m 不变。该函数返回一个pair 类型对象,包含指向键为 e.first 的元素的 map 迭代器,以及一个 bool 类型的对象,表示是否插入了该元素
m.insert(beg,end )beg 和 end 是标记元素范围的迭代器,其中的元素必须为m.value_type 类型的键-值对。对于该范围内的所有元素,如果它的键在 m 中不存在, 则将该键及其关联的值插入到 m。返回 void 类型
m.insert(iter,e)e 是一个用在 m 上的 value_type 类型的值。如果键( e.first )不在 m 中,则创建新元素,并以迭代器 iter 为起点搜索新元素存储的位置。返回一个迭代器,指向 m 中具有给定键的元素

*
用 insert 代替下标运算:
word_count.insert(map<string,int>::value_type("WB", 1));
在添加新 map 元素时,使用 insert 成员可避免使用下标操作符所带来的副作用:不必要的初始化。带有一个键-值 pair 形参的 insert 版本将返回一个值:包含一个迭代器和一个 bool 值的 pair 对象,其中迭代器指向 map 中具有相应键的元素,而 bool 值则表示是否插入了该元素。如果该键已在容器中,则其关联的值保持不变,返回的 bool 值为 true。

使用下标查找 map 中的元素存在一个很危险的副作用:如果该键不在 map 容器中,那么下标操作会插入一个具有该键的新元素。map 容器提供了两个操作:count 和 find,用于检查某个键是否存在而不会插入该键。

表2.4 不修改 map 对象的查询操作

m.count(k)返回 m 中 k 的出现次数
m.find(k)如果 m 容器中存在按 k 索引的元素,则返回指向该元素的迭代器。如果不存在,则返回超出末端迭代器

*

表2.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 类型

*
“单词转换”程序:这个程序求解的问题是:给出一个 string 对象,把它转换为另一个 string 对象。本程序的输入是两个文件。第一个文件包括了若干单词对,每对的第一个单词将出现在输入的字符串中, 而第二个单词则是用于输出。本质上,这个文件提供的是单词转换的集合——在遇到第一个单词时, 应该将之替换为第二个单词。第二个文件则提供了需要转换的文本。

#include<iostream>
#include<sstream>//string streams operation:istringstream,ostringstream,stringstream
#include<fstream>//files operation: ifstream, ofstream,fstream
#include<string>
#include<map>
#include<utility>
#include<vector>

using namespace std;
//open files
ifstream &open_file(ifstream &in, const string &file){
    in.close(); //close it incase it was already open
    in.clear();//clear any exiting errors
    //if the open fails, the stream will be in an invalid state
    in.open(file.c_str());
     return in;//if open successfully, "in" will be attached to files. otherwise, it will be errors
}

int main(int argc, char *argv[]){
    //arg[1] and argv[2] store two files to transfer words
    ifstream map_file;
    map<string, string> trans_map;//store wrod pairs
    string key,value;
    if(argc != 3) // incorrect command parameters
        throw runtime_error("Wrong number of arguments");
    if(!open_file(map_file, argv[1]))
        throw runtime_error("no transformation files");
    while(map_file >> key >> value)// insert strings of files into a map
        trans_map.insert(make_pair(key, value));

    ifstream input;
    if(!open_file(input, argv[2]))
        throw runtime_error("no input file");
    string line;
    while(getline(input, line)){//get text by line
        //associate line with istringstream to read by word
        istringstream stream(line);
        string word;
        bool firstword = true;//label the head of a line 
        while(stream >> word){
            map<string, string>::const_iterator map_it = trans_map.find(word);
            if(map_it != trans_map.end())//find successfully
                word = map_it -> second;
            if(firstword)
                firstword = false;// do not need to insert a blank in the head of a line
            else
                cout << " ";
            cout << word;
        }
        cout << endl;
    }

    return 0;
}

以上内容为学习笔记,摘选自《c++ primer》第四版


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值