Primer C++ 学习笔记(第十一章)

本书为Primer C++ 中文第五版

练习题笔记

在这里插入图片描述

(11.1)
map是关键字-值对的集合。vector是值的集合。
map是关联容器,高效实现“按值访问元素”。容器里的元素是按关键字值存储的,关键字和元素数据建立对应关系。底层数据结构是红黑树,哈希表等,可高效地实现按关键字查找、添加、删除等操作。
vector是顺序容器,元素是按顺序存储。操作是按位置进行的。
(11.2)
vector 适用于顺序的添加,非大量频繁的删除操作
list 适用于大量的删除操作
deque 适用于两头添加的操作
set 适用于判断是否存在的操作
map 适用于键值对的操作
(11.3)
void test3() {
    map<string, size_t> word_count;
    set<string> exclude = {"The", "But", "And", "Or", "An", "A",
                            "the", "but", "and", "or", "an", "a"};
    string word;
    while(cin >> word && word != "q") {
        //find 返回一个迭代器,如果存在返回关键字,否则返回尾后迭代器
        if(exclude.find(word) == exclude.end())
            //map类型以关键字为下标,获得其对应的值
            ++word_count[word];
    }
    for(const auto &w : word_count) {
        cout << w.first << " occurs " << w.second
            << ((w.second > 1)? " times " : " time ") << endl;
    }
}

(11.4)
void test4() {
    map<string, size_t> word_count;
    set<string> exclude = {"The", "But", "And", "Or", "An", "A",
                            "the", "but", "and", "or", "an", "a"};
    string word;
    while(cin >> word && word != "q") {
        int len = word.size() - 1;
        if(word[len] == ',' || word[len] == '.' || word[len] == '!' || word[len] == '?') {
            word = word.substr(0, len);
        }
        transform(word.begin(), word.end(), word.begin(), ::tolower);
        if(exclude.find(word) == exclude.end())
            ++word_count[word];
    }
    for(const auto &w : word_count) {
        cout << w.first << " occurs " << w.second
            << ((w.second > 1)? " times " : " time ") << endl;
    }
}

在这里插入图片描述

(11.5)
map 用来键值对的操作
set 用来判断某个值是否存在
(11.6)
set 可以快速的判断某个值是否存在
list 则是按位置或者顺序对里面的值进行访问操作
(11.7)
void test7() {
    map<string, vector<string>> home;
    set<string> firstname;
    string s,e;
    while(cin >> s >> e && s != "q") {
        if(firstname.find(s) == firstname.end()) {
            firstname.insert(s);
            cout << "creat a new home" << endl;
            home[s].push_back(e);
        }else {
            cout << "home have exited" << endl;
            home[s].push_back(e);
        }
    }
    for(auto iter = home.begin(); iter != home.end(); ++iter) {
        cout << iter->first << " ";
        for(auto scan = iter->second.begin(); scan < iter->second.end(); ++scan) {
            cout << *scan << " ";
        }
        cout << endl;
    }
}
(11.8)
/**
 *使用vector中的find函数需要加上头文件#include <algorithm>;
 *而且比较繁琐
 */
void test8() {
    vector<string> exclude = {"The", "But", "And", "Or", "An", "A",
                            "the", "but", "and", "or", "an", "a"};
    string s;
    while(cin >> s && s != "q") {
        auto iter = find(exclude.begin(), exclude.end(), s);
        if(iter == exclude.end()) cout << "not exits" << endl;
        else cout << "exits" << endl;
    }
}

在这里插入图片描述

(11.9)
void test9() {
    map<string, list<int>> strlst;
    ifstream fin("test.txt");
    int l = 1;
    while(!fin.eof()) {
        string line;
        getline(fin, line);
        stringstream input(line);
        string word;
        while(input >> word) {
            cout << word << " ";
            if(strlst.find(word) == strlst.end()) {
                list<int> def;
                def.push_back(l);
                strlst[word] = def;
            }else {
                auto lst = strlst[word];
                auto findif = find(lst.begin(), lst.end(), l);
                if(findif == lst.end()) {
                    strlst[word].push_back(l);
                }
            }
        }
        cout << endl;
        l++;
    }
    for(auto scan = strlst.begin(); scan != strlst.end(); ++scan) {
        cout << scan->first << "\t";
        for(auto lst = scan->second.begin(); lst != scan->second.end(); ++lst) {
            cout << *lst << "\t";
        }
        cout << "\n";
    }
}
(11.10)
关联容器对关键字类型有一些限制。对于有序容器map,multimap,set,multiset,关键字类型必须定义元素比较的方法。
(11.11)
回顾:
decltype((variable))的结果永远是引用
而decltype(variable)只有当variable本身就是一个引用时,才是引用,引用必须被初始化
decltype(f()) sum = x; //sum的类型就是函数f的返回类型
typedef a b; 给a取个别名为b
可以利用类型别名,
typedef bool (*pf)(const Sales_data &lhs, const Sales_data &rhs);
multiset<Sales_data, pf> bookstore(compareIsbn);

在这里插入图片描述

(11.12)
void test12() {
    vector<pair<string, int>> res;
    string s;
    int n = 0;
    while(cin >>s && s != "q") {
        pair<string, int> p = {s, n};
        res.push_back(p);
        n++;
    }
    for(auto p : res) {
        cout << p.first << " " << p.second << endl;
    }
}
(11.13)
void test13() {
    vector<pair<string, int>> res;
    vector<pair<string, int>> res1;
    vector<pair<string, int>> res2;
    string s;
    int n = 0;
    while(cin >>s && s != "q") {
        pair<string, int> p = {s, n};
        pair<string, int> p1(s, n);
        res.push_back(p);
        res1.push_back(make_pair(s, n));
        res2.push_back(p1);
        n++;
    }
    for(auto p : res) {
        cout << p.first << " " << p.second << endl;
    }
    for(auto p : res1) {
        cout << p.first << " " << p.second << endl;
    }
    for(auto p : res2) {
        cout << p.first << " " << p.second << endl;
    }
}
//个人更喜欢使用make_pair()
(11.14)
void test14() {
    map<string, pair<string, string>> people;
    string fn, la, bir;
    while(cin >> fn >> la >> bir && fn != "q") {
        people[fn] = make_pair(la, bir);
    }
    for(auto p : people) {
        cout << p.first << p.second.first << p.second.second << endl;
    }
}

在这里插入图片描述

(11.15)
map<int, vector<int>> test;
key_type : int
mapped_type : vector<int>
value_type : pair<const int, vector<int>>
(11.16)
void test16() {
    map<string, int> m;
    int n = 0;
    string s = "a";
    for(int i = 0; i < 5; ++i) {
        m[s] = i;
        s = s.append(s);
    }
    for(auto sc = m.begin(); sc != m.end(); ++sc) {
        cout << sc->first << " " << sc->second << endl;
    }
}
(11.17)
因为set的迭代器是const的,只允许访问元素
所以前两个非法,后面两个合法
(11.18)
map<const string, size_t>::iterator
(11.19)
multiset<Sales_data, pf>::iterator iter = bookstore.begin();

在这里插入图片描述

(11.20)
void test20() {
    map<string, size_t> word_count;
    string word;
    while(cin >> word && word != "q") {
        auto ret = word_count.insert({word, 1});
        //insert插入成功res.second为true,ret.first指向word_count[word]的迭代器
        if(!ret.second) ret.first->second++;
//        ++word_count.insert({word, 0}).first->second;
    }
    for(const auto &w : word_count) {
        cout << w.first << " occurs " << w.second
            << ((w.second > 1)? " times " : " time ") << endl;
    }
}

(11.21)
首先是在map word_count插入值
然后 word_count.insert({word,0}).first 是指向word_count[word]的迭代器
最后将word_count[word]值增加1
等价于上一题的写法
(11.22)
参数类型: pair<string, vector<int>>
返回类型: pair<map<string, vector<int>>::iterator, bool>
(11.23)
void test23() {
    multimap<string, string> home;
    string fn, la;
    while(cin >> fn >> la && fn != "q") {
        home.insert({fn, la});
    }
    for(auto iter = home.begin(); iter != home.end(); ++iter) {
        cout << iter->first << " " << iter->second << endl;
    }
}

在这里插入图片描述

(11.24)
先创建一个关键字为0,值为0的pair类元素。然后将该关键字的对应的值赋值为1(11.25)
v是一个空的容器,用下标访问它的非法位置0的元素会引发错误造成系统崩溃。
(11.26)
对map进行下标操作的类型是该map的key_type
下标运算符返回的类型是该map的mapped_type
eg.map<string, int> msi;可以利用string类型的对msi进行下标操作,返回的类型为int类型

在这里插入图片描述

(11.27)
只关心一个特定元素是否已在容器中,find是最佳选择。
对于不允许重复关键字的容器find和count作用是一样的。
对于允许重复关键字的容器,count会统计有多少个元素相同的关键字。
(11.28)
void test28() {
    map<string, vector<int>> msv;
    string s = "a";
    vector<int> vi;
    for(int i = 0; i < 5; ++i) {
        vi.push_back(i);
        msv.insert({s, vi});
        s = s.append(s);
    }
    for(auto i : msv.find("aaaa")->second) {
        cout << i << " ";
    }
    cout << endl;
}
(11.29)
接受一个关键字,返回一个迭代器
lower_bound();指向第一个具有给定关键字的元素
upper_bound();指向最后一个匹配给定关键字的元素之后的位置
若元素不存在,返回一个相等的迭代器,指向一个不影响排序的关键字插入位置。

接受一个关键字,返回一个迭代器pair
equal_range();若存在,第一个迭代器指向第一个与关键字匹配的元素,第二个迭代器指向最后一个匹配元素之后的位置。若未找到匹配元素,则两个迭代器都指向关键字可以插入的位置。
(11.30)
pos.first代表与关键字匹配元素的迭代器
pos.first->second代表该关键字指向的值
(11.31)
(11.32)
void test3132() {
    multimap<string, string> books;
    books.insert({"JY", "TLBB"});
    books.insert({"YG", "BLSMY"});
    books.insert({"YG", "BCSJ"});
    books.insert({"LLXXS", "JPM"});
    cout << "origin:" << endl;
    for(auto b : books) {
        cout << b.first << " " << b.second << endl;
    }
    cout << "delete:" << endl;
    for(auto pos = books.equal_range("JY"); pos.first != pos.second; ++pos.first) {
        cout << pos.first->first << " " << pos.first->second << endl;
        books.erase(pos.first->first);
    }
    cout << "end:" << endl;
    for(auto begin = books.begin(); begin != books.end(); ++begin) {
        cout << begin->first << " " << begin->second << endl;
    }
}

在这里插入图片描述

(11.33)
#include <iostream>
#include <map>
#include <string>
#include <fstream>
#include <sstream>

using namespace std;

map<string, string> buildMap(ifstream &map_file) {
    map<string, string> trans_map;
    string key;
    string 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: " + key);
    }
    return trans_map;
}

const string & transform(const string &s, const map<string, string> &m) {
    auto map_it = m.find(s);
    if(map_it != m.end())
        return map_it->second;
    else
        return s;
}

void word_transform(ifstream &map_file, ifstream &input) {
    auto trans_map = buildMap(map_file);
    string text;
    while(getline(input, text)) {
        istringstream stream(text);
        string word;
        bool firstword = true;
        while(stream >> word) {
            if(firstword)
                firstword = false;
            else
                cout << " ";
            if(word[word.size()-1] == ',' || word[word.size()-1] == '.' || word[word.size()-1] == '?' || word[word.size()-1] == '!') word = word.substr(0, word.size() - 1);
            cout << transform(word, trans_map);
        }
        cout << endl;
    }
}

void test33() {
    ifstream fmap("map.txt");
    ifstream finput("input.txt");
    word_transform(fmap, finput);
}

int main() {
    test33();
    return 0;
}

(11.34)
会使得本来不存在转换的值,经过下标操作创建该值存到map中
(11.35)
当key不存在的时候,这两种情况都会是创建
但是当key已经存在的时候,第一种情况是替换key的value,而第二种则是什么也不会做
(11.36)
例子中已经进行了判断,如果没有对应的value,则会抛出runtime_error

在这里插入图片描述在这里插入图片描述

(11.37)
无序容器不需要维护元素的排序,在性能测试和调优工作有着很好的效果。如果不是必须对关键字排序,用无序容器有着更好的性能。
(11.38)
略略略了,只需要把map改成unordered_mao即可
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值