C++ primer(第五版)第9章习题答案

第九章 顺序容器

9.1

(a)std::set是最好的。现在,我们可以选择list,比vector或deque更好,因为我们可能需要经常在中间插入元素来保持按字母顺序排序。

(b)deque,如果程序需要在前面和后面插入或删除元素,而不是在中间插入或删除元素,请使用deque.

(c)vector,不需要在前面或后面插入或删除。如果你的程序有很多小元素和空间开销,不要使用list或forward-list。

 

9.2

list<deque<int>> ldi;

 

9.3

-它们指向同一个容器中的元素,或者是容器最后一个元素之后的位置。

-可以通过反复递增begin来到达end.

 

9.4

bool find(vector<int>::iterator beg, vector<int>::iterator end, int value)
{
    for (auto iter = beg; iter != end; ++iter)
        if (*iter == value) return true;
    return false;
}

 

9.5

vector<int>::iterator find(vector<int>::iterator beg, vector<int>::iterator end, int value)
{
    for (auto iter = beg; iter != end; ++iter)
        if (*iter == value) return iter;
    return end;
}

 

9.6

运算符< 不能用于list容器。

while(iter1 != iter2)

 

9.7

vector<int>:: size_type

 

9.8

list<string>::iterator || list<string>::const_iterator

list<string>::iterator

 

9.9

cbegin是一个const成员,返回容器的const_iterator类型。

begin是一个非常量成员,返回容器的iterator类型。

 

9.10

it1: vector<int>::iterator

it2,3,4 : vector<int>::const_iterator

 

9.11

vector<int> vec;    // 0
vector<int> vec(10);    // 10个0
vector<int> vec(10,1);  // 10个1
vector<int> vec{1,2,3,4,5}; // 1,2,3,4,5
vector<int> vec(other_vec); // same as other_vec
vector<int> vec(other_vec.begin(), other_vec.end()); // same as other_vec

 

9.12

将另一个容器作为参数(数组除外)的构造函数必须使得两个容器的容器类型和元素类型相同。它还将把接收到的容器的所有元素复制到新容器中:

list<int> numbers = {1, 2, 3, 4, 5};
list<int> numbers2(numbers);        // ok, numbers2 has the same elements as numbers
vector<int> numbers3(numbers);      // error: no matching function for call...
list<double> numbers4(numbers);     // error: no matching function for call...

采用两个迭代器作为参数的构造函数不要求容器类型相同。此外,只要能够将要复制的元素转换为要初始化的容器的元素类型,新容器和原始容器中的元素类型就可能不同。它还将只复制由接收的迭代器分隔的对象。

list<int> numbers = {1, 2, 3, 4, 5};
list<int> numbers2(numbers.begin(), numbers.end);        // ok, numbers2 has the same elements as numbers
vector<int> numbers3(numbers.begin(), --numbers.end());  // ok, numbers3 is {1, 2, 3, 4}
list<double> numbers4(++numbers.beg(), --numbers.end());        // ok, numbers4 is {2, 3, 4}
forward_list<float> numbers5(numbers.begin(), numbers.end());   // ok, number5 is {1, 2, 3, 4, 5}

 

9.13

#include <iostream>
#include <string>
#include <vector>
#include <list>

using std::list;
using std::vector;
using std::cout;
using std::endl;

int main()
{
    list<int> ilst(5, 4);
    vector<int> ivc(5, 5);

    //! from list<int> to vector<double>
    vector<double> dvc(ilst.begin(), ilst.end());
    for (auto i : ilst) cout << i;
    cout << endl;
    for (auto t : dvc) cout << t;
    cout << endl;

    //! from vector<int> to vector<double>
    vector<double> dvc2(ivc.begin(), ivc.end());
    for (auto i : ivc) cout << i;
    cout << endl;
    for (auto t : dvc2) cout << t;

    return 0;
}

 

9.14

#include <iostream>
#include <string>
#include <vector>
#include <list>

int main()
{
    std::list<const char*> l{"Mooophy", "pezy", "Queeuqueg"};
    std::vector<std::string> v;
    v.assign(l.cbegin(), l.cend());

    for (const auto& ch : v) std::cout << ch << std::endl;

    return 0;
}

 

9.15

#include <iostream>
#include <vector>

int main()
{
    std::vector<int> vec1{1, 2, 3, 4, 5};
    std::vector<int> vec2{1, 2, 3, 4, 5};
    std::vector<int> vec3{1, 2, 3, 4};

    std::cout << std::boolalpha << (vec1 == vec2) << std::endl;
    std::cout << std::boolalpha << (vec1 == vec3) << std::endl;

    return 0;
}

 

9.16

#include <iostream>
#include <vector>
#include <list>

int main()
{
    std::list<int> list{1, 2, 3, 4, 5};
    std::vector<int> vec1{1, 2, 3, 4, 5};
    std::vector<int> vec2{1, 2, 3, 4};

    std::cout << std::boolalpha
              << (std::vector<int>(list.begin(), list.end()) == vec1)
              << std::endl;
    std::cout << std::boolalpha
              << (std::vector<int>(list.begin(), list.end()) == vec2)
              << std::endl;
}

 

9.17

除了无序关联容器外的所有容器都支持关系运算符,两边的运算对象必须是相同类型的容器,且必须保存相同类型的元素,该元素类型必须支持所需运算符。

 

9.18

#include <iostream>
#include <string>
#include <deque>

using std::string;
using std::deque;
using std::cout;
using std::cin;
using std::endl;

int main()
{
    deque<string> input;
    for (string str; cin >> str; input.push_back(str))
        ;
    for (auto iter = input.cbegin(); iter != input.cend(); ++iter)
        cout << *iter << endl;

    return 0;
}

 

9.19

#include <iostream>
#include <string>
#include <list>

using std::string;
using std::list;
using std::cout;
using std::cin;
using std::endl;

int main()
{
    list<string> input;
    for (string str; cin >> str; input.push_back(str))
        ;
    for (auto iter = input.cbegin(); iter != input.cend(); ++iter)
        cout << *iter << endl;

    return 0;
}

 

9.20

#include <iostream>
#include <deque>
#include <list>
using std::deque;
using std::list;
using std::cout;
using std::cin;
using std::endl;

int main()
{
    list<int> l{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    deque<int> odd, even;
    for (auto i : l) (i & 0x1 ? odd : even).push_back(i);

    for (auto i : odd) cout << i << " ";
    cout << endl;
    for (auto i : even) cout << i << " ";
    cout << endl;

    return 0;
}

 

9.21

一样。第一次调用insert会将我们刚刚读入的string插入到iter所指的元素之前的位置。insert返回的迭代器恰好指向这个新元素。我们将此迭代器赋予iter并重复循环,读取下一个单词。只要继续有单词读入,每步while循环就会将一个新元素插入到iter之前,并将iter改变为新加入元素的位置。此元素为新的首元素。因此,每步循环将一个新元素插入到vector首元素之前的位置。

 

9.22

1.是一个死循环

2.向一个vector,string,deque插入元素会使所有指向容器的迭代器,引用和指针失效。

 

9.23

都是指向同一个元素的相同值。

 

9.24

#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v;
    std::cout << v.at(
        0); // terminating with uncaught exception of type std::out_of_range
    std::cout << v[0];       // Segmentation fault: 11
    std::cout << v.front();  // Segmentation fault: 11
    std::cout << *v.begin(); // Segmentation fault: 11
    return 0;
}

 

9.25

如果相等,什么也不会发生。

如果elem2是尾后迭代器,从elem1开始到最后都会被删除。

如果都是尾后迭代器,什么也不会发生。

 

9.26

#include <iostream>
#include <vector>
#include <list>

using std::vector;
using std::list;
using std::cout;
using std::endl;
using std::end;

int main()
{
    int ia[] = {0, 1, 1, 2, 3, 5, 8, 13, 21, 55, 89};

    //! init
    vector<int> vec(ia, end(ia));
    list<int> lst(vec.begin(), vec.end());

    //! remove odd value
    for (auto it = lst.begin(); it != lst.end();)
        if (*it & 0x1)
            it = lst.erase(it);
        else
            ++it;

    //! remove even value
    for (auto it = vec.begin(); it != vec.end();)
        if (!(*it & 0x1))
            it = vec.erase(it);
        else
            ++it;

    //! print
    cout << "list : ";
    for (auto i : lst) cout << i << " ";
    cout << "\nvector : ";
    for (auto i : vec) cout << i << " ";
    cout << std::endl;

    return 0;
}

 

9.27


#include <iostream>
#include <forward_list>

using std::forward_list;
using std::cout;
using std::endl;

int main()
{
    forward_list<int> flst = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    for (auto prev = flst.before_begin(), curr = flst.begin();
         curr != flst.end();)
        if (*curr & 0x1)
            curr = flst.erase_after(prev);
        else
            prev = curr++;

    for (auto i : flst) cout << i << " ";
    cout << endl;
}

 

9.28

void find_and_insert(forward_list<string> &list, const string& to_find, const string& to_add)
{
    auto prev = list.before_begin();
    auto size = std::distance(list.begin(), list.end());
    for (auto curr = list.begin(); curr != list.end(); prev = curr++)
        if (*curr == to_find) list.insert_after(curr, to_add);
    if (size == std::distance(list.begin(), list.end())) list.insert_after(prev, to_add);
}

 

9.29

添加75个新元素,并进行值初始化。

末尾删除90个元素。

 

9.30

如果容器保存的是类类型元素,且resize向容器添加新元素,则我们必须提供初始值,或者元素类型必须提供一个默认构造函数。

 

9.31

可以,注意list,forward_list没有迭代器+-n运算


#include <iostream>
#include <list>

using std::list;
using std::cout;
using std::endl;
using std::advance;

int main()
{
    list<int> vi = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    auto iter = vi.begin();
    while (iter != vi.end()) {
        if (*iter % 2) {
            iter = vi.insert(iter, *iter);
            advance(iter, 2);
        }
        else
            iter = vi.erase(iter);
    }

    for (auto i : vi) cout << i << " ";

    return 0;
}
#include <iostream>
#include <forward_list>

using std::forward_list;
using std::cout;
using std::endl;
using std::advance;

int main()
{
    forward_list<int> vi = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    auto iter = vi.begin(), prev = vi.before_begin();
    while (iter != vi.end()) {
        if (*iter % 2) {
            iter = vi.insert_after(prev, *iter);
            advance(iter, 2);
            advance(prev, 2);
        }
        else
            iter = vi.erase_after(prev);
    }

    for (auto i : vi) cout << i << " ";

    return 0;
}

 

9.32

求值顺序不确定。

 

9.33

会失效,在向容器添加元素后,如果容器是vector或string,且存储空间被重新分配,则指向容器的迭代器,指针和引用都会失效。

 

9.34

循环范围有错,iter指向也不对。

#include <iostream>
using std::cout;
using std::endl;

#include <vector>
using std::vector;

int main()
{
    vector<int> vi = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    auto iter = vi.begin();
    while (iter != vi.end()) {
        if (*iter % 2) {
            iter = vi.insert(iter, *iter);
            ++iter;
        }
        ++iter;
    }

    for (auto i : vi) cout << i << " ";

    return 0;
}

 

9.35

size:指它已经保存的元素的数目

capacity:在不分配新的内存空间的前提下它最多可以保存多少元素

 

9.36

不可能。

 

9.37

list元素不需要连续存储。array有着固定的大小。

 

9.38

我的是成倍增长。

#include <iostream>
#include <string>
#include <vector>

int main()
{
    std::vector<std::string> v;
    std::string word;

    while (std::cin >> word) {
        v.push_back(word);
        std::cout << v.capacity() << "\n";
    }

    return 0;
}

 

9.39

调用resize或reserve时给定的大小超过当前的capacity,vector才可能重新分配空间。

 

9.40

readsizecapacity
2563841024
5127681024
100015002000(clang is 2048)
104815722048

 

9.41

#include <iostream>
#include <vector>
#include <string>

using std::vector;
using std::cout;
using std::endl;
using std::string;

int main()
{
    vector<char> vec{'p', 'e', 'z', 'y'};
    string str(vec.begin(), vec.end());

    cout << str << endl;

    return 0;
}

 

9.42

svec.reserve(120)

 

9.43

#include <string>
using std::string;

#include <iostream>

void Replace(string& s, const string& oldVal, const string& newVal)
{
    for (auto beg = s.begin(); std::distance(beg, s.end()) >=
                               std::distance(oldVal.begin(), oldVal.end());) {
        if (string{beg, beg + oldVal.size()} == oldVal) {
            beg = s.erase(beg, beg + oldVal.size());
            beg = s.insert(beg, newVal.cbegin(), newVal.cend());
            std::advance(beg, newVal.size());
        }
        else
            ++beg;
    }
}

int main()
{
    {
        string str{"To drive straight thru is a foolish, tho courageous act."};
        Replace(str, "thru", "through");
        Replace(str, "tho", "though");
        std::cout << str << std::endl;
    }
    {
        string str{
            "To drive straight thruthru is a foolish, thotho courageous act."};
        Replace(str, "thru", "through");
        Replace(str, "tho", "though");
        std::cout << str << std::endl;
    }
    {
        string str{"To drive straight thru is a foolish, tho courageous act."};
        Replace(str, "thru", "thruthru");
        Replace(str, "tho", "though");
        std::cout << str << std::endl;
    }
    {
        string str{"my world is a big world"};
        Replace(str, "world",
                "worldddddddddddddddddddddddddddddddddddddddddddddddd");
        std::cout << str << std::endl;
    }
    return 0;
}

 

9.44

#include <iostream>
#include <string>

using std::cout;
using std::endl;
using std::string;
using std::prev;

void Replace(string& s, string const& oldVal, string const& newVal)
{
    for (string::size_type i = 0; i != s.size(); ++i)
        if (s.substr(i, oldVal.size()) == oldVal) {
            s.replace(i, oldVal.size(), newVal);
            i += newVal.size() - 1;
        }
}

int main()
{
    string str{"To drive straight thru is a foolish, tho courageous act."};
    Replace(str, "tho", "though");
    Replace(str, "thru", "through");
    cout << str << endl;
}

 

9.45

#include <iostream>
#include <string>

//! Exercise 9.45
std::string pre_suffix(const std::string& name, const std::string& pre,
                       const std::string& su);

int main()
{
    std::string name("alan");
    std::cout << pre_suffix(name, "Mr.", ",Jr.") << std::endl;

    return 0;
}

inline std::string pre_suffix(const std::string& name, const std::string& pre,
                              const std::string& su)
{
    auto ret = name;
    ret.insert(ret.begin(), pre.begin(), pre.end());
    ret.append(su);

    return ret;
}

 

9.46

#include <iostream>
#include <string>

std::string pre_suffix(const std::string& name, const std::string& pre,
                       const std::string& su)
{
    std::string ret(name);
    ret.insert(0, pre);
    ret.insert(ret.size(), su);

    return ret;
}

int main()
{
    std::string name("alan");
    std::cout << pre_suffix(name, "Mr.", ",Jr.");

    return 0;
}

 

9.47


#include <string>
#include <iostream>

using std::string;
using std::cout;
using std::endl;

int main()
{
    string numbers{"0123456789"};
    string alphabet{"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"};
    string str{"ab2c3d7R4E6"};

    cout << "numeric characters: ";
    for (string::size_type pos = 0;
         (pos = str.find_first_of(numbers, pos)) != string::npos; ++pos)
        cout << str[pos] << " ";
    cout << "\nalphabetic characters: ";
    for (string::size_type pos = 0;
         (pos = str.find_first_of(alphabet, pos)) != string::npos; ++pos)
        cout << str[pos] << " ";
    cout << endl;

    return 0;
}

 

#include <string>
#include <iostream>

using std::string;
using std::cout;
using std::endl;

int main()
{
    string numbers{"0123456789"};
    string alphabet{"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"};
    string str{"ab2c3d7R4E6"};

    cout << "numeric characters: ";
    for (string::size_type pos = 0;
         (pos = str.find_first_not_of(alphabet, pos)) != string::npos; ++pos)
        cout << str[pos] << " ";
    cout << "\nalphabetic characters: ";
    for (string::size_type pos = 0;
         (pos = str.find_first_not_of(numbers, pos)) != string::npos; ++pos)
        cout << str[pos] << " ";
    cout << endl;

    return 0;
}

 

9.48

string::npos

 

9.49

#include <string>
#include <fstream>
#include <iostream>

using std::string;
using std::ifstream;
using std::cout;
using std::endl;

int main()
{
    ifstream ifs("../data/letter.txt");
    if (!ifs) return -1;
    string longest_word;
    for (string word; ifs >> word;)
        if (word.find_first_not_of("aceimnorsuvwxz") == string::npos &&
            word.size() > longest_word.size())
            longest_word = word;

    cout << longest_word << endl;
}

 

9.50


#include <iostream>
#include <string>
#include <vector>

int sum_for_int(const std::vector<std::string> &v)
{
    int sum = 0;
    for (auto const& s : v) sum += std::stoi(s);
    return sum;
}

float sum_for_float(const std::vector<std::string> &v)
{
    float sum = 0.0;
    for (auto const& s : v) sum += std::stof(s);
    return sum;
}

int main()
{
    std::vector<std::string> v = {"1", "2", "3", "4.5"};
    std::cout << sum_for_int(v) << std::endl;
    std::cout << sum_for_float(v) << std::endl;

    return 0;
}

 

9.51

#include <array>
#include <iostream>
#include <string>

class Date {
public:
    explicit Date(const std::string& str = "");
    void Print();
    unsigned year = 1970;
    unsigned month = 1;
    unsigned day = 1;

private:
    std::array<std::string, 12> month_names{"Jan", "Feb", "Mar", "Apr", "May", "Jun",
                                            "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
    unsigned MonthFromName(const std::string& str);
};

Date::Date(const std::string& str)
{
    if (str.empty()) return;
    std::string delimiters{" ,/"};
    auto month_day_delim_pos = str.find_first_of(delimiters);
    if (month_day_delim_pos == std::string::npos)
        throw std::invalid_argument("This format is not supported now.");
    month = MonthFromName(str.substr(0, month_day_delim_pos));
    auto day_year_delim_pos = str.find_first_of(delimiters, month_day_delim_pos + 1);
    auto day_len = day_year_delim_pos - month_day_delim_pos - 1;
    day = std::stoi(str.substr(month_day_delim_pos + 1, day_len));
    year = std::stoi(str.substr(day_year_delim_pos + 1));
}

void Date::Print()
{
    std::cout << year << "-" << month << "-" << day << "\n";
}

unsigned Date::MonthFromName(const std::string& str)
{
    if (str.empty()) return 0;
    if (std::isdigit(str[0])) return std::stoi(str);
    for (size_t i = 0; i != 12; ++i) {
        if (str.find(month_names[i]) != std::string::npos) return i + 1;
    }
    return 0; //  not found
}

int main()
{
    { //  default case
        auto date = Date();
        date.Print();
    }
    { //  case 0: January 1, 1900
        auto date = Date("January 1, 1900");
        date.Print();
    }
    { //  case 1: 1/1/1900
        auto date = Date("1/1/1900");
        date.Print();
    }
    { //  case 2: Jan 1, 1900
        auto date = Date("Jan 1, 1900");
        date.Print();
    }
}

 

9.52

#include <stack>
using std::stack;

#include <string>
using std::string;

#include <iostream>
using std::cout;
using std::endl;

int main()
{
    auto& expr = "This is (Mooophy(awesome)((((wooooooooo))))) and (ocxs) over";
    auto repl = '#';
    auto seen = 0;

    stack<char> stk;

    for (auto c : expr) {
        stk.push(c);
        if (c == '(') ++seen;   // open
        if (seen && c == ')') { // pop elements down to the stack
            while (stk.top() != '(') stk.pop();
            stk.pop();      // including the open parenthesis
            stk.push(repl); // push a value indicate it was replaced
            --seen;         // close
        }
    }

    // Test
    string output;
    for (; !stk.empty(); stk.pop()) output.insert(output.begin(), stk.top());
    cout << output << endl; // "This is # and # over"
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值