C++ Primer第5版 第十一章课后练习答案

练习11.1

map和vector相比是通过关键字而不是位置来查找值。

练习11.2

list:需要在中间进行操作的情况。

vector:若没有必要使用其他容器则优先使用

deque:只需要在头尾进行操作的情况

map:字典

set:key-value相同的集合

练习11.3

int main(int argc, char* argv[])
{
    map<string, size_t> word_count;
    string word;
    while (cin >> word) {
        ++word_count[word];
    }
    for (const auto& w : word_count) {
        cout << w.first << " " << w.second << endl;
    }
}

练习11.4

int main(int argc, char* argv[])
{
    map<string, size_t> word_count;
    string word;
    while (cin >> word) {
        word.erase(remove_if(word.begin(), word.end(), [](char& c) {if (isupper(c)) { tolower(c); } return ispunct(c); }));
        ++word_count[word];
    }
    for (const auto& w : word_count) {
        cout << w.first << " " << w.second << endl;
    }
}

练习11.5

map是关键字-值对的集合,set是关键字的集合,看使用场景需要key-value还是key集合

练习11.6

set是关联容器,进行查找、修改操作效率高

list是顺序容器,插入删除操作效率低,随机访问速度慢

练习11.7

int main(int argc, char* argv[])
{
    map<string, vector<string>> familys;
    string surname, name;
    while (cin >> surname>> name) {
        familys[surname].emplace_back(name);
    }
    for (const auto& f : familys) {
        cout << f.first << ":";
        for (const auto& n : f.second) {
            cout << n << " ";
        }
        cout << endl;
    }
}

练习11.8

int main(int argc, char* argv[])
{
    vector<string> words;
    string word;
    while (cin >> word) {
        words.emplace_back(word);
    }
    auto it = unique(words.begin(), words.end());
    words.erase(it, words.end());
}

set查找速度快

练习11.9

map<string, list<size_t>> m;

练习11.10

不能,因为map所提供的操作必须在关键字类型上定义一个严格弱序,而迭代器之间是无法比较的

练习11.11

int main(int argc, char* argv[])
{
    typedef bool (*Comp)(const Sales_data&, const Sales_data&);//和decltype(compareIsbn)*等价
    multiset<Sales_data, Comp>bookStore(Comp);
}

练习11.12

int main(int argc, char* argv[])
{
    vector<string>str_vec(10);
    vector<int> i_vec(10);
    vector<pair<string, int>> psi1;
    vector<pair<string, int>> psi2;
    vector<pair<string, int>> psi3;
    string str, int num;
    for (auto i = 0; i < 10; ++i) {
        cin >> str >> num;
        str_vec.emplace_back(str);
        i_vec.emplace_back(num);
    }
    for (auto i = 0; i < 10; ++i) {
        psi1.push_back({ str_vec[i],i_vec[i] });
        psi1.emplace_back(pair<string, int>(str_vec[i], i_vec[i]));
        psi1.emplace_back(make_pair(str_vec[i], i_vec[i]));
    } 
}

练习11.13

int main(int argc, char* argv[])
{
    vector<string>str_vec(10);
    vector<int> i_vec(10);
    vector<pair<string, int>> psi1;
    vector<pair<string, int>> psi2;
    vector<pair<string, int>> psi3;
    string str, int num;
    for (auto i = 0; i < 10; ++i) {
        cin >> str >> num;
        str_vec.emplace_back(str);
        i_vec.emplace_back(num);
    }
    for (auto i = 0; i < 10; ++i) {
        psi1.push_back({ str_vec[i],i_vec[i] });//不能用emplace_back来进行pair的列表初始化
        psi1.emplace_back(pair<string, int>(str_vec[i], i_vec[i]));
        psi1.emplace_back(make_pair(str_vec[i], i_vec[i]));
    } 
}

练习11.14

int main(int argc, char* argv[])
{
    map<string, vector<pair<string, string>>> familys;
    string surname, name, birthday;
    while (cin >> surname >> name>>birthday) {
        familys[surname].emplace_back(make_pair(name, birthday));
    }
    for (const auto& f : familys) {
        cout << f.first << ":";
        for (const auto& n : f.second) {
            cout << n.first << "'s birthday is "<<n.second<<" ";
        }
        cout << endl;
    }
}

练习11.15

mapped_type:vector<int>

key_type:int

value_type:pair<const int,vector<int>>

练习11.16

int main(int argc, char* argv[])
{
    map<int, int>i_i_map;
    auto it = i_i_map.begin();
    (*it).second = 5;
}

练习11.17

copy(v.begin(), v.end(), inserter(c, c.end()));//调用insert成员函数插入到multiset尾后迭代器之前
copy(v.begin(), v.end(), back_inserter(c));//multiset没有push_back成员函数,因此无法使用
copy(c.begin(), c.end(), inserter(v,v.end()));//调用insert成员函数插入到vector尾后迭代器之前
copy(c.begin(), c.end(), back_inserter(v));//调用push_back成员函数插入到vector尾后迭代器之前

练习11.18

map<string,size_t>::iterator

练习11.19

int main(int argc, char* argv[])
{
    typedef bool (*Comp)(const Sales_data&, const Sales_data&);//和decltype(compareIsbn)*等价
    multiset<Sales_data, Comp>bookStore(compareIsbn);
    multiset<Sales_data, Comp>::iterator it = bookStore.begin();
}

练习11.20

int main(int argc, char* argv[])
{
    map<string, size_t> word_count;
    string word;
    while (cin >> word) {
        auto ret = word_count.insert({ word,1 });
        if (!ret.second)
            ++ret.first->second;
    }
    for (const auto& w : word_count) {
        cout << w.first << " " << w.second << endl;
    }
}
//下标操作更容易编写和阅读

练习11.21

输入word,并将其设置为关键字插入到容器中,对应的值为0,然后对值进行递增,若此时容器中已有重复关键字则直接对该关键字对应的值进行递增。

练习11.22

参数类型:pair<string,vector<int>>

返回类型:map<string,vector<int>>::iterator

练习11.23

int main(int argc, char* argv[])
{
    multimap<string, vector<string>> familys;
    string surname, name, vector<string>names;
    while (cin >> surname) {
        while (cin >> name){
            names.emplace_back(name);
        } 
        familys.insert({ surname,names });
    }
    for (const auto& f : familys) {
        cout << f.first << ":";
        for (const auto& n : f.second) {
            cout << n << " ";
        }
        cout << endl;
    }
}

练习11.24

 查找m中关键字为0的元素,若没找到则插入一个关键字为0的元素,返回该元素的mapped_type对象,并为其赋值1

练习11.25

查找v中索引为0的元素,并为该地址上的元素赋值为1。若v的size为0则返回out_of_range错误

练习11.26

 可以用key_type来对一个map进行下标操作。下标运算符返回的类型是mapped_type。

int main(int argc, char* argv[])
{
    map<int,int> m;
    map<int, int>::key_type kt = 0;
    map<int, int>::mapped_type mt = m[kt];
    cout << kt << " " << mt;
}

练习11.27

对于计算允许重复关键字容器中某个关键字数量或者是使用find和count来输出容器中所有某个关键字元素时会使用count;

查找不允许重复关键字容器的元素或者判断容器中是否存在某个要查找关键字元素时会使用dind

练习11.28

int main(int argc, char* argv[])
{
    map<string, vector<int>> stoiv_m{ { "123",{1,2,3} },{ "456",{4,5,6} }, { "789",{7,8,9} } };
    auto m_ite = stoiv_m.find("123");
    for (const auto& it : m_ite->second)
        cout << it << " ";
}

练习11.29

int main(int argc, char* argv[])
{
    map<string, vector<int>> stoiv_m{ { "123",{1,2,3} },{ "456",{4,5,6} }, { "789",{7,8,9} } };
    for (auto m_uite = stoiv_m.upper_bound("0"), m_lite = stoiv_m.lower_bound("0"); m_uite != m_lite; ++m_lite) {
        for (const auto& it : m_uite->second)
            cout << it << " ";
    }
    for (auto m_eite = stoiv_m.equal_range("0"); m_eite.first != m_eite.second; ++m_eite.first) {
        for (const auto& it : m_eite.first->second)
            cout << it << " ";
    }
}

upper_bound和lower_bound都返回相等的迭代器-指向一个不影响排序的关键字插入位置

equal_range返回的pair的first成员和upper_bound都返回相等的迭代器,second成员和lower_bound都返回相等的迭代器

练习11.30

输出返回的pair的pos的迭代器first中的值

练习11.31

int main(int argc, char* argv[])
{
    multimap<string, string> authortobook_m{ { "123","1,2,3" },{ "456","4,5,6" }, { "789","7,8,9" } };
    auto it = authortobook_m.find("123");
    if(it!=authortobook_m.end())
        authortobook_m.erase(it->first);
}

练习11.32

int main(int argc, char* argv[])
{
    multimap<string, string> authortobook_m{ { "123","1,2,3" },{ "123","1,4,5" } ,{ "456","4,5,6" }, { "789","7,8,9" } };
    set<string> s;
    for (const auto& author : authortobook_m) {
        s.insert(author.first);
    }
    for (const auto& author : s) {
        cout << author << ": ";
        for (auto m = authortobook_m.equal_range(author); m.first != m.second; ++m.first) {
            cout << m.first->second << " ";
        }
        cout << endl;
    }   
}

练习11.33

map<string, string> buildMap(ifstream& map_file)
{
    map<string, string> trans_map;
    string key, value;

    while (map_file >> key && getline(map_file, value)) {
        if (value.size() > 1) {
            trans_map[key] = value.substr(1);           // 去掉value前的空格
        }
        else {
            throw runtime_error("no rules for " + key);
        }
    }
    return trans_map;
}

const string& transform(const string& s, const map<string, string>& m)
{
    auto map_iter = m.find(s);

    if (map_iter != m.end()) {
        return map_iter->second;
    }
    // if find the word in map, return the phrase. else return the origin word.
    else {
        return s;
    }
}

void wordTransform(ifstream& map_file, ifstream& input)
{
    auto trans_map = buildMap(map_file);
    string text;

    while (getline(input, text)) {
        istringstream stream(text);
        string word;
        bool first_word = true;

        while (stream >> word) {
            if (first_word) {
                first_word = false;
            }
            else {
                cout << " ";
            }
            cout << transform(word, trans_map);
        }
        cout << endl;
    }
}

int main(int argc, char* argv[])
{
    string transform_file = argv[1];
    string input_file = argv[2];

    ifstream trans(transform_file);
    ifstream input(input_file);

    if (trans && input) {
        wordTransform(trans, input);
    }
    else {
        cout << "open file error!" << endl;
    }
    return 0;
}

练习11.34

当find替换成下标运算符,若关键还未在map中,下标操作会插入一个具有给定关键字的元素

练习11.35

如果转换文件中有重复key,若使用下标进行插入,则value是最后文件中key对应的最后一个短语。而如果使用insert,则key对应的是第一个短语。(因为只有当key不在trans_map中时才会进行插入操作)

练习11.36

如果文件中的某一行包含一个关键字、一个空格,然后就结束了,那程序会抛出runtime_error,提示no rules for "key".

练习11.37

无序容器的优势:无需维护元素的序关系,拥有更好的平均性能,使用通常也更简单

有序容器的优势:时间复杂度稳定,可以顺序遍历元素

练习11.38

单词计数程序

int main(int argc, char* argv[])
{
    unordered_map<string, size_t> word_count;
    string word;
    while (cin >> word) {
        ++word_count[word];
    }
    for (const auto& w : word_count) {
        cout << w.first << " " << w.second << endl;
    }
}

单词转换程序

unordered_map<string, string> buildMap(ifstream& map_file)
{
    unordered_map<string, string> trans_map;
    string key, value;

    while (map_file >> key && getline(map_file, value)) {
        if (value.size() > 1) {
            trans_map[key] = value.substr(1);           // 去掉value前的空格
        }
        else {
            throw runtime_error("no rules for " + key);
        }
    }
    return trans_map;
}

const string& transform(const string& s, const unordered_map<string, string>& m)
{
    auto map_iter = m.find(s);//当find替换成下标运算符,若关键还未在map中,下标操作会插入一个具有给定关键字的元素

    if (map_iter != m.end()) {
        return map_iter->second;
    }
    else {
        return s;
    }
}

void wordTransform(ifstream& map_file, ifstream& input)
{
    auto trans_map = buildMap(map_file);
    string text;

    while (getline(input, text)) {
        istringstream stream(text);
        string word;
        bool first_word = true;

        while (stream >> word) {
            if (first_word) {
                first_word = false;
            }
            else {
                cout << " ";
            }
            cout << transform(word, trans_map);
        }
        cout << endl;
    }
}

int main(int argc, char* argv[])
{
    string transform_file = argv[1];
    string input_file = argv[2];

    ifstream trans(transform_file);
    ifstream input(input_file);

    if (trans && input) {
        wordTransform(trans, input);
    }
    else {
        cout << "open file error!" << endl;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/GodZhuan/p/13963311.html