《C++ Primer》第11章 11.1节习题答案

《C++ Primer》第11章 关联容器

导读本章介绍了标准库关联容器,包括:

●关联容器的概念和简单使用。

●关联容器涉及的类型和操作,特别是与顺序容器的差异。

●无序关联容器,特别是与有序容器的差异。

本章练习的最重要目的是让读者理解关联容器的思想及其与顺序容器的差异,学会根据实际问题的特点选择适合的容器。具体内容除了关联容器基本类型和操作的练习之外,还有一些较大的练习以及与实际问题相关的练习。

11.1节使用关联容器 习题答案

练习11.1:描述map和vector的不同。

【出题思路】

理解顺序容器和关联容器的不同。

【解答】

学习关联容器,理解与顺序容器的不同,最关键的是理解其基础的数据结构,随后它所表现出来的一些性质就很自然能够理解了。两类容器的根本差别在于,顺序容器中的元素是“顺序”存储的(链表容器中的元素虽然不是在内存中“连续”存储的,但仍然是按“顺序”存储的)。理解“顺序”的关键,是理解容器支持的操作形式以及效率。

对于vector这样的顺序容器,元素在其中按顺序存储,每个元素有唯一对应的位置编号,所有操作都是按编号(位置)进行的。例如,获取元素(头、尾、用下标获取任意位置)、插入删除元素(头、尾、任意位置)、遍历元素(按元素位置顺序逐一访问)。底层的数据结构是数组、链表,简单但已能保证上述操作的高效。而对于依赖值的元素访问,例如查找(搜索)给定值(find),在这种数据结构上的实现是要通过遍历完成的,效率不佳。

而map这种关联容器,就是为了高效实现“按值访问元素”这类操作而设计的。为了达到这一目的,容器中的元素是按关键字值存储的,关键字值与元素数据建立起对应关系,这就是“关联”的含义。底层数据结构是红黑树、哈希表等,可高效实现按关键字值查找、添加、删除元素等操作。

练习11.2:分别给出最适合使用list、vector、deque、map以及set的例子。

【出题思路】

理解顺序容器和关联容器的适用范围。

【解答】

若元素很小(例如int),大致数量预先可知,在程序运行过程中不会剧烈变化,大部分情况下只在末尾添加或删除需要频繁访问任意位置的元素,则vector可带来最高的效率。若需要频繁在头部和尾部添加或删除元素,则deque是最好的选择。如果元素较大(如大的类对象),数量预先不知道,或是程序运行过程中频繁变化,对元素的访问更多是顺序访问全部或很多元素,则list很适合。

map很适合对一些对象按它们的某个特征进行访问的情形。典型的例如按学生的名字来查询学生信息,即可将学生名字作为关键字,将学生信息作为元素值,保存在map中。

set,顾名思义,就是集合类型。当需要保存特定的值集合——通常是满足/不满足某种要求的值集合,用set最为方便。

练习11.3:编写你自己的单词计数程序。

【出题思路】

练习map的简单使用。

【解答】

参照本节例子完成完整程序即可。

#include <iostream>
#include <fstream>
#include <map>
#include <string>
#include <algorithm>

using namespace std;

int main(int argc, const char * argv[])
{
    ifstream in(argv[1]);
    if(!in)
    {
        cout << "打开输入文件失败!" << endl;
        exit(1);
    }
    
    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_03.txt文件内容如下:

the quick red fox jumps over the the slow over red turtle

设置命令行参数:

 运行结果:

 练习11.4:扩展你的程序,忽略大小写和标点。例如,example.、example,和Example,应该递增相同的计数器。

【出题思路】

此题并非练习set的使用,而是字符串的处理。

【解答】

编写函数trans,将单词中的标点去掉,将大写都转换为小写。具体方法是:遍历字符串,对每个字符首先检查是否是大写(ASCII值在A和Z之间),若是,将其转换为小写(减去A,加上a);否则,检查它是否带标点,若是,将其删除。最终,将转换好的字符串返回。

#include <iostream>
#include <fstream>
#include <map>
#include <string>
#include <algorithm>

using namespace std;

string &trans(string &s)
{
    for(int p = 0; p < s.size(); p++)
    {
        if(s[p] >= 'A' && s[p] <= 'Z')
            s[p] -= ('A' - 'a');
        else if(s[p] == ',' || s[p] == '.')
            s.erase(p, 1);
    }
    return s;
}


int main(int argc, const char * argv[])
{
    ifstream in(argv[1]);
    if(!in)
    {
        cout << "打开输入文件失败!" << endl;
        exit(1);
    }

    map<string, size_t> word_count;//string到count的映射
    string word;
    while(in >> word)
        ++word_count[trans(word)];  //这个单词的出现次为数加1

    for(const auto &w: word_count)//对map中的每个元素
    {
        //打印结果
        cout << w.first << "出现了 " << w.second << " 次" << endl;
    }
    return 0;
}

data11_04.txt文件内容如下:

The quick Red fox. jumps Over the, the Slow. over red. turtle

设置命令行参数:

 运行结果:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值