《C++ Primer》第11章 关联容器
11.4节 无序容器 习题答案
练习11.37:一个无序容器与其有序版本相比有何优势?有序版本有何优势?
【出题思路】
理解无序关联容器与有序版本的差异。
【解答】
无序版本通常性能更好,使用也更为简单。有序版本的优势是维护了关键字的序。当元素的关键字类型没有明显的序关系,或是维护元素的序代价非常高时,无序容器非常有用。但当应用要求必须维护元素的序时,有序版本就是唯一的选择。
练习11.38:用unordered_map重写单词计数程序(参见11.1节,第375页)和单词转换程序(参见11.3.6节,第391页)。
【出题思路】
本题练习使用无序关联容器。
【解答】
对单词计数程序仅有的两处修改是将包含的头文件map改为unordered_map,以及将word_count的类型由map改为unordered_map。尝试编译、运行此程序,你会发现,由于无序容器不维护元素的序,程序的输出结果与第3题的输出结果的顺序是不同的。
#include <iostream>
#include <fstream>
#include <unordered_map>
#include <string>
#include <algorithm>
using std::cout;
using std::endl;
using std::ifstream;
using std::unordered_map;
using std::string;
//using namespace std;
int main(int argc, const char * argv[])
{
ifstream in(argv[1]);
if(!in)
{
cout << "打开输入文件失败!" << endl;
exit(1);
}
unordered_map<string, size_t> word_count; //string到count的映射
string word;
while(in >> word)
++word_count[word];//这个单词的出现次数加1
for(const auto &w: word_count)//对map中的每个元素
{
//打印结果
cout << w.first << "出出了 " << w.second << " 次" << endl;
}
return 0;
}
data11_38.txt文件内容如下:
the quick red fox jumps over the the slow over red turtle
设置命令行参数:
运行结果:
单词转换程序的修改类似。由于程序中不再有元素内容的顺序输出,因此输出结果与有序版本没有什么不同。
#include <iostream>
#include <unordered_map>
#include <vector>
#include <iostream>
#include <fstream>
#include <string>
#include <stdexcept>
#include <sstream>
using namespace std;
unordered_map<string, string> buildMap(ifstream &map_file)
{
unordered_map<string, string> trans_map;//保存转换规则
string key;//要转换的单词
string value;//用来替换的内容
//读取第一个单词存入key,这一行的剩余内容存入value
while(map_file >> key && getline(map_file, value))
{
if(value.size() > 1)//检查是否确实存在转换规则
trans_map[key] = value.substr(1);//跳过前导空白
else
throw runtime_error("no rule for " + key);
}
return trans_map;
}
const string &transform(const string &s, const unordered_map<string, string> &m)
{
//完成具本体转换工作,这个函数是程序的核心
auto map_it = m.find(s);
//如果这个单词在转换映射表中
if(map_it != m.cend())
return map_it->second;//用映射表指定内容替换单词
else
return s;//否则原样返回单词
}
//第一个参数为转换规则文件
//第二个参数是要转换的文本文件
void word_transform(ifstream &map_file, ifstream &input)
{
auto trans_map = buildMap(map_file);//保存转换规则
//调试用:映射表创建好后打印它
cout << "Here is our transformation map:\n\n";
for(auto entry: trans_map)
cout << "key: " << entry.first << "\tvalue: " << entry.second << endl;
cout << "\n\n";
//对给定文本进行转换
string text;//保存从输入读取的每一行
while(getline(input, text)) //从输入读取一行
{
istringstream stream(text);//读取每个单词
string word;
bool firstword = true;//控制是否打印空格
while(stream >> word)
{
if(firstword)
firstword = false;
else
cout << " ";//打单词间打印空格
//转换结果可能是另一个字符串也可能是原单词
cout << transform(word, trans_map);//打印结果
}
cout << endl;//当前行转换完毕,打印回车
}
}
int main(int argc, const char * argv[])
{
//打开两个文件并检查是否打开成功
if(argc != 3)
throw runtime_error("wrong number of arguments");
ifstream map_file(argv[1]);//打开转换规则文件
if(!map_file)//检查是否打开成功
throw runtime_error("no transformation file");
ifstream input(argv[2]);//打开转换的文件
if(!input)//检查是否打开成功
throw runtime_error("no input file");
word_transform(map_file, input);
return 0;//退出主函数时文件会自动关闭
}
data11_38_map.txt文件内容如下:
brb be right back
k okay?
y why
r are
u you
pic picture
the thanks!
l8r later
data11_38_input.txt文件内容如下:
where r u
y don’t u send me a pic
k the l8r
设置命令行参数:
运行结果: