C++Primer第五版——第九章习题

第九章 顺序容器练习题

9.1
(a) list
(b) deque
(c) vector
9.2
list<deque<int>> a;
9.3
指向同一个容器,并且end不在begin之前。
9.4
bool find(vector<int>::iterator b, vector<int>::iterator e, int x) {
    while (b != e) {
        if (*b == x) return true;
        b ++;
    }
    return false;
}
9.5
using vit = vector<int>::iterator;
vit find(vit b, vit e, int x) {
    while (b != e) {
        if (*b == x) return b;
        b ++;
    }
    cout << "vector中不存在" << x << endl;
    exit(0);
}
9.6
list迭代器不支持 < 运算符
9.7
vector<int>::size_type
9.8
读:list<string>::const_iterator
写:list<string>::iterator
9.9
begin返回的iterator要看容器类型,如果容器是const则返回const_iterator;如果容器非const,就返回iterator。而cbegin则显式的指定返回类型为const_iterator,与容器无关。
9.10
it1: vector<int> iterator;
it2, it3, it4: vector<int> const_iterator;
由于 it1 与 it2 的类型不一致,所以书中的 auto it1 = v1.begin(), it2 = v2.begin() 有误。
9.11
(1) vector<int> a; // 空的vector
(2) vector<int> a(10); // 大小为10,值被默认初始化为0
(3) vector<int> a(10, 1); // 大小为10,值被初始化为1
(4)	vector<int> a = {1, 2, 3, 4, 5} // 列表初始化
(5) vector<int> b;
    vector<int> a(b); 	
    vector<int> a = b; // 拷贝初始化,与上面等价
(6) vector<int> a(b.begin(), b.end()); // 迭代器范围初始化
9.12
接受容器要求容器的类型和其元素类型一致才行,接受迭代器范围则不要求容器类型一致,其元素类型也可以不一致,只要能够转换即可。
9.13
使用迭代器范围初始化
9.14
使用assign
9.15
可直接使用==运算符
9.16
bool judge(vector<int> a, list<int> b) {
    if (a.size() != b.size()) return false;
    vector<int>::const_iterator vit1 = a.cbegin(), vit2 = a.cend();
    list<int>::const_iterator lit = b.cbegin();
    while (vit1 != vit2) {
        if (*vit1 != *lit) return false;
        vit1 ++;
        lit ++;
    }
    return true;
}
9.17
(1) c1 和 c2 必须是同一类型的容器,且必须保存相同类型的元素;
(2) 容器中保存的元素必须定义了 < 运算符。
9.18
void code_9_18() {
    string str;
    deque<string> ds;
    while (cin >> str) ds.push_back(str);
    using ds_cit = deque<string>::const_iterator;
    for (ds_cit it = ds.cbegin(); it != ds.cend(); it ++) cout << *it << endl; 
}
9.19
void code_9_19() {
    string str;
    list<string> ls;
    while (cin >> str) ls.push_back(str);
    using ls_cit = list<string>::const_iterator;
    for (ls_cit it = ls.cbegin(); it != ls.cend(); it ++) cout << *it << endl;
}
9.20
void code_9_20() {
    list<int> ilst = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    deque<int> odd, even;
    for (const auto & it : ilst) {
        if (it & 1) odd.push_back(it);
        else even.push_back(it);
    }
    cout << "odd: ";
    for (const auto & it : odd) cout << it << " ";
    cout << endl << "even: ";
    for (const auto & it : even) cout << it << " ";
}
9.21
由于vector是顺序容器,所以在执行insert操作时,从iter开始之后的所有的元素都要后移一位。
9.22
	(1) 迭代器iter没有递增;
    (2) vector在insert操作后,原迭代器会失效(P305)
修改如下:
void code_9_22() {
    vector<int> iv = {2, 2, 1, 3, 5};
    int some_val = 2;
    vector<int>::iterator iter = iv.begin(), mid = iv.begin() + iv.size() / 2;
    int tmp = iv.size() / 2;
    while (iter != mid) {
        if (*iter == some_val) {
            iter = iv.insert(iter, 2 * some_val) + 1;
            mid = iv.begin() + (++tmp);
        }
        iter ++;
    }
    for (const auto &it : iv) cout << it << " ";
}
9.23
都指向一个元素,也是 c 中的唯一元素
9.24
vector<int> iv;
//terminate called after throwing an instance of 'std::out_of_range'
int a = iv.at(0);
// 以下均运行时错误
int b = iv[0]; 
int c = iv.front();
int d = *iv.begin();
9.25
(1) elem1 = elem2: 不发生删除
(2) elem2 = 尾后迭代器:删除从elem1开始之后的所有元素(包括elem1)
(3) elem1 = elem2 = 尾后迭代器:不发生删除
9.26
void code_9_26() {
    int ia[] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 55, 89 };
    vector<int> iv;
    list<int> il;
    iv.assign(begin(ia), end(ia));
    il.assign(begin(ia), end(ia));
    vector<int>::iterator it1 = iv.begin();
    list<int>::iterator it2 = il.begin();
    while (it1 != iv.end() && it2 != il.end()) {
        if (*it2 & 1) {
            it2 = il.erase(it2);
            it1 ++;
        } else {
            it1 = iv.erase(it1);
            it2 ++;
        }
    }
    for (const auto &it : iv) cout << it << " "; cout << endl;
    for (const auto &it : il) cout << it << " "; cout << endl;
}
9.27
void code_9_27() {
    forward_list<int> flst = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 55, 89 };
    auto p = flst.before_begin(), c = flst.begin();
    while (c != flst.end()) {
        if (*c & 1) {
            c = flst.erase_after(p);
        } else {
            p = c;
            c ++;
        }
    }
    for (const auto &it : flst) cout << it << " ";
}
9.28
void code_9_28(forward_list<string> &flst, string s1, string s2) {
    forward_list<string>::const_iterator it1 = flst.cbegin(), it2 = flst.cbefore_begin();
    while (it1 != flst.cend()) {
        if (*it1 == s1) { // 找到第一个string
            flst.insert_after(it1, s2);
            return;
        }
        it1 ++;
        it2 ++;
    }
    flst.insert_after(it2, s2);
}
9.29
vec.resize(100): 将vec扩展到100个元素,后面新加的75个元素都为0
vec.resize(10): 删除vec后面的90个元素,保留前10个
9.30
接受单个参数,如果容器保存的是类类型元素,则该类必须提供一个默认构造函数
9.31
对于list和forward_list的迭代器不支持+=运算符,并且forward_list没有insert和erase方法
对于list只需要将 iter+=2; 修改为 iter++; iter++; 即可
对于 forward_list:
forward_list<int> fli = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
auto it1 = fli.before_begin(), it2 = fli.begin();
while (it2 != fli.end()) {
    if (*it2 % 2) {
        it1 = fli.insert_after(it1, *it2);
        it2 ++;
        it1 ++;
    } else {
        it2 = fli.erase_after(it1);
    }
}
9.32
不合法。
函数调用时,参数的进栈顺序是从右往左,所以会先执行 *iter++;(第一个参数iter后进栈,并发生了改变)
由于 * 和 ++ 优先级一样,但 *iter++是从右往左运算,所以先计算 ++,再计算*,但是由于iter++是先返回iter,再执行++运算,所以*iter等价于 *iter; iter++;这样导致实际的插入位置是原iter的后一个位置,所以返回后iter指向当前插入的元素(但是在原处理奇数元素的后面),而后再执行 iter+=2 就会跳过一个元素没有处理,并且这可能会导致 iter 迭代器失效。
将 iter += 2; 改为 iter ++; 即可。
9.33
begin 会失效
9.34
程序的目的是想将奇数在它位置上复制一份,如 { 1,2,3,4 } 执行应得到:{ 1,1,2,3,3,4 }
但是由于在插入元素的 if 条件里迭代器没有自增到当前处理的元素,导致了死循环。
9.35
size: 容器中已经保存的元素的个数
capacity: 容器在不分配新的内存空间的前提下最多可以保存多少个元素
9.36
不可能
9.37
对于 array 来说,在创建的时候就已经固定了大小,不可以改变。
对于 list 来说,它每一个元素在内存中的位置不一定是连续的,所以不需要 capacity。
9.38
void code_9_38() {
    vector<int> vi;
    int x;
    while (cin >> x) {
        vi.push_back(x);
        cout << "size = " << vi.size() << " capactity = " << vi.capacity() << endl;
    }
}
9.39
创建一个保存 string 的 vector,并为容器分配可以保存1024个元素的内存空间。
再从输入中读取单词保存到容器中,最后扩展容器的 size,后面有三分之一的元素为空字符串。resize 并不会减少容器的容量,但可能会增加。如果 resize 操作后,size > 1024(针对本题分配好的空间),那么 capacity 会增加。
9.40
void code_9_40(int n) {
    vector<string> svec;
    svec.reserve(1024);
    for (int i = 1; i <= n; i ++) svec.push_back("hi");
    svec.resize(svec.size() + svec.size() / 2);
    cout << "读取" << n << "个单词:size = " << svec.size() << " capacity = " << svec.capacity() << endl;
}

调用函数如下:    
    code_9_40(256);
    code_9_40(512);
    code_9_40(1000);
    code_9_40(1048);

输出结果如下:
    读取256个单词:size = 384 capacity = 1024  
    读取512个单词:size = 768 capacity = 1024  
    读取1000个单词:size = 1500 capacity = 2000
    读取1048个单词:size = 1572 capacity = 2048
    
9.41
void code_9_41() {
    vector<char> vc = { 'h', 'e', 'l', 'l', 'o' };
    string s(vc.cbegin(), vc.cend());
    cout << s << endl;
}
9.42
可以使用 reserve 预分配出足够的容量
9.43
void code_9_43(string &s, string oldVal, string newVal) {
    using sit = string::iterator;
    for (sit it1 = s.begin(); it1 + oldVal.size() - 1 < s.end(); it1 ++) {
        sit it2 = it1, it3 = oldVal.begin();
        while (*it2 == *it3) {
            it2 ++;
            it3 ++;
            if (it3 == oldVal.end()) {
                it1 = s.erase(it1, it2);
                it1 = s.insert(it1, newVal.cbegin(), newVal.cend());
                it1 += newVal.size() - 1;
                break;
            }
        }
    }
}
9.44
void code_9_44(string &s, string oldVal, string newVal) {
    for (int i = 0; i + oldVal.size() - 1 < s.size(); i ++) {
        if (s.substr(i, oldVal.size()) == oldVal) {
            s.replace(i, oldVal.size(), newVal);
            i += newVal.size() - 1;
        }
    }
}
9.45
string code_9_45(const string &name, const string &pre, const string &suf) {
    string ret = name;
    ret.insert(ret.begin(), pre.cbegin(), pre.cend());
    ret.append(suf);
    return ret;
}
9.46
string code_9_46(const string &name, const string &pre, const string &suf) {
    string ret = name;
    ret.insert(0, pre, 0, pre.size());
    ret.insert(ret.size(), suf, 0, suf.size());
    return ret;
}
9.47
void code_9_47() {
    string::size_type pos = 0;
    string s("ab2c3d7R4E6"), numbers("0123456789");
    while ((pos = s.find_first_of(numbers, pos)) != string::npos) {
        cout << s[pos] << endl;
        pos ++;
    }
    puts("========================");
    pos = 0;
    while ((pos = s.find_first_not_of(numbers, pos)) != string::npos) {
        cout << s[pos] << endl;
        pos ++;
    }
}
9.48
string::npos
9.49
void code_9_49() {
    string valid("acemnorsuvwxz");
    ifstream in("words.txt");
    string s, mx_s;
    while (in >> s) {
        if (s.find_first_not_of(valid) == string::npos && s.size() > mx_s.size()) mx_s = s;
    }
    cout << mx_s << endl;
}
9.50
void code_9_50() {
    vector<string> vs_i(10, "100"), vs_d(10, "10.5");
    int i_sum = 0; double d_sum = 0;
    for (const auto &it : vs_i) i_sum += stoi(it);
    for (const auto &it : vs_d) d_sum += stod(it);
    cout << i_sum << " " << d_sum << endl;
}
9.51
void code_9_51() {
    class Date {
    public:
        vector<string> mons = { "", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec" };
        unsigned year, month, day;
        Date(string str) {
            // 根据 '空格',','和'/'划分为三个字符串
            string _year, _month, _day;
            string::size_type pos1 = str.find_first_of(", /");
            string::size_type pos2 = str.find_last_of(", /");
            _month = str.substr(0, pos1);
            _day = str.substr(pos1 + 1, pos2 - pos1 - 1);
            _year = str.substr(pos2 + 1);
            // 如果月份用英文表达
            if (_month.find_first_of("0123456789") == string::npos) {
                for (int i = 1; i <= 12; i ++) {
                    if (_month.find(mons[i]) != string::npos) {
                        _month = to_string(i);
                        break;
                    }
                }
            }
            year = stoi(_year);
            month = stoi(_month);
            day = stoi(_day);
        };

        void print() {
            cout << year << "年" << month << "月" << day << "日" << endl;
        }
    };
    string tmp;
    while (getline(cin, tmp)) {
        Date date(tmp);
        date.print();
    }
}
9.52
void code_9_52(string str) {
    // str = (((3*5)+10)*(((20-4)*5)/5))
    stack<int> intSk;
    stack<char> chSk;
    for (int i = 0; i < str.size(); i ++) {
        if (str[i] == ')') {
            int b = intSk.top(); intSk.pop();
            int a = intSk.top(); intSk.pop();
            char c = chSk.top(); chSk.pop(); chSk.pop(); // 先弹出操作符,再弹出左括号
            switch (c) {
                case '+':
                    intSk.push(a + b);
                    break;
                case '-':
                    intSk.push(a - b);
                    break;
                case '*':
                    intSk.push(a * b);
                    break;
                case '/':
                    intSk.push(a / b);
                    break;
            }
        } else if (str[i] >= '0' && str[i] <= '9') {
            string::size_type pos = str.find_first_not_of("0123456789", i + 1);
            intSk.push(stoi(str.substr(i, pos - i)));
            i = pos - 1;
        } else chSk.push(str[i]);
    }
    cout << str << " = " << intSk.top() << endl; // 最后的结果
}
posted @ 2022-03-13 10:14  nonameless  阅读(55)  评论(1编辑  收藏  举报