《c++ primer》 第九章顺序容器课后练习

练习 9.3 构成迭代器范围的迭代器有何限制?

        1、两个迭代器必须指向同一个容器中的元素,或者是容器最后一个元素之后的位置。

        2、end不能再begin之前。

练习9.4 编写函数,接收一对指向vector<int>的迭代器和一个int值。在两个迭代器指定的范围中查找给定的值,返回一个bool值来支出是否找到。

bool judge( vector<int>::iterator left, vector<int>::iterator right, const int target) {
        while(left != right){
            if(*left == target)
                return true;
            ++left;
        }
     return false;
 }

练习9.5 重写上一题的函数,返回一个迭代器指向找到的元素。注意,程序必须处理未找到给定值的情况。

 vector<int>::iterator judge( vector<int>::iterator left, vector<int>::iterator right, const int target) {
        while(left != right){
            if(*left == target)
                return left;
            ++left;
        }
     return right ;
 }

练习9.6  下面程序有何错误?你应该如何修改它?

list<int> lst1;
list<int>::iterator iter1 = lst1.begin(),iter2 = lst1.end();
while (iter1 < iter2) /* ... */

迭代器不支持 <运算。

练习9.7  为了索引int的vector中的元素,应该使用什么类型?

vector<int>::type_size

练习9.8  为了读取string的list中的元素,应该使用什么类型?如果写入list,又应该使用什么类型?

读取:list<string>::const_iterator;

写入:list<sting>::iterator;

练习9.9 begin和cbegin两个函数有什么不同?

begin 返回容器的迭代器类型,返回iterator 还是const_iterator取决于容器类型,如果容器为const的返回的就是const_iterator,不是const的就返回iterator。

cbegin返回的是const_iterator。

练习9.10  下面4个对象分别是什么类型?
vector<int> v1;
const vector<int> v2;
auto it1 = v1.begin(), it2 = v2.begin();
auto it3 = v1.cbegin(), it4 = v2.cbegin();

it1 是iterator。it2是const_iterator。it3是const_iterator。it4是const_iterator。

练习9.11 对于6种创建和初始化vector对象的方法,每一种都给出一个实例。解释每个vector包含什么值。

vector<int> v1{1,2,3,4,5}; //包含1,2,3,4,5 这5个值
     vector<int> v2;            //空的
     vector<int> v3(v1);        // 复制了v1的值
     vector<int> v4 = v1;       //同上一个
     vector<int> v5 = {1, 2, 3, 4, 5};// 同 v1
     vector<int> v6(v1.begin(),--v1.end());//复制了v1的1,2,3,4

练习9.12  对于接受一个容器创建其拷贝的构造函数,和接受两个迭代器创建拷贝的构造函数,解释它们的不同。

对于接受一个容器创建其拷贝的构造函数,对于容器类型和元素类型必须一致。

对于接收两个迭代器所创建拷贝的构造函数,容器类型可以不同,元素类型可以隐式转换即可。

练习9.13  如何从一个list<int>初始化一个vector<double>?从一个vector<int>又该如何创建?编写代码验证你的答案。

     list<int> l(10,1);
     vector<double> dvec(l.cbegin(),l.cend());

练习9.14 编写程序,将一个list中的char *指针元素赋值给一个vector中的string。

list<const char *> l{"This ","is ","test"};
     vector<string> sv;
     sv.assign(l.cbegin(),l.cend());
     for(auto it:sv)
        cout<<it<<endl;

练习9.15 编写程序,判定两个vector<int>是否相等。

vector<int> v1{1,2,3,4,5};
     vector<int> v2{1,2,3,6};
    if (v1 == v2)
        cout<<"v1 = v2";
    else cout<<"v1 != v2";

练习9.16 重写上一题的程序,比较一个list<int>中的元素和一个vector<int>中的元素。

vector<int> v1{1,2,3,4,5};
     list<int>   v2{1,2,3,4,6};
     auto it1 = v1.cbegin();
     auto it2 = v2.cbegin();
    if (v1.size() != v2.size())
        cout<<"两个容器中元素不相等";
    else {
        while(it1 != v1.cend())
            if (*it1 == *it2){
                ++it1;
                ++it2;
            }
            else {
                cout << "两个容器不相等";
                break;
            }
        if (it1 == v1.cend())
            cout << "两个容器相等";


    }

练习9.17 假定c1和c2是两个容器,下面的比较操作有何限制?

                        if(c1 < c2)

两个容器的类型和元素类型必须一致,且不能是无序关联数组。元素类型如果是自定义的类型,必须自己定义了 < 操作。

 练习9.18 编写程序,从标准输入读取string序列,存入一个deque中。编写一个循环,用迭代器打印deque的值。

string word;
     deque<string> ds;
     while(cin>>word)
         ds.push_back(word);
     deque<string>::const_iterator it1 = ds.cbegin(),it2 = ds.cend();
     while(it1 != it2)
         cout<<*it1++<<endl;

练习9.19 重写上题的程序,用list代替deque。

string word;
     list<string> ds;
     while(cin>>word)
         ds.push_back(word);
     list<string>::const_iterator it1 = ds.cbegin(),it2 = ds.cend();
     while(it1 != it2)
         cout<<*it1++<<endl;

练习9.20 编写程序,从一个list<int>拷贝元素到两个deque中。值为偶数的所有元素都拷贝到一个deque中,而奇数值元素都拷贝到另一个deque中。

list<int> li = {1,2,3,4,5,6,7,8};
    deque<int> di1,di2;
    list<int>::const_iterator left = li.cbegin(), right = li.cend();
    while(left != right){
        if (*left % 2)
            di2.push_back(*left++);
        else
            di1.push_back(*left++);
    }
    cout<<"di1:";
    for (auto temp : di1) {
        cout<<temp<<" ";
    }
    cout<<endl;
    cout<<"di2:";
    for (auto temp : di2) {
        cout<<temp<<" ";
    }
    cout<<endl;

练习9.22  假定iv是一个int的vector,下面的程序存在什么错误?你将如何修改?
vector<int>::iterator iter = iv.begin(), mid = iv.begin() + iv.size() / 2;
while (iter != mid)
if (*iter == some_val)
iv.insert(iter, 2 * some_val);

错误:iter的值不会发生变换,循环陷入死循环。mid的值在插入后变得非法。

练习9.24 编写程序,分别使用at、下标运算符、front和begin提取一个vector中的第一个元素。在一个空vector上测试你的程序。

    vector<int> vec;
    cout<<vec.at(0)<<endl;
    cout<<vec[0]<<endl;
    cout<<vec.front()<<endl;
    cout<<*vec.begin()<<endl;

练习9.25    对于第312页中删除一个范围内的元素的程序,如果elem1与elem2相等会发生什么?如果elem2是尾后迭代器,或者elem1和elem2皆为尾后迭代器,又会发生什么?

如果相等,不作任何操作。如果elem2是尾后迭代器,函数行为无定义。elem1和elem2皆为尾后迭代器,不进行操作,然后返回的是尾后迭代器。

 练习9.26 使用下面代码定义的ia,将ia拷贝到一个vector和一个list中。使用单迭代器版本的erase从list中删除奇数元素,从vector中删除偶数元素。
int ia[] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 55, 89 };

int ia[] = {0,1,2,3,5,8,13,21,55,89};
     vector<int> ivec;
     list<int> ili;
    for (auto i : ia) {
        ivec.push_back(i);
        ili.push_back(i);
    }
    for(auto i: ivec)
        cout<<i<<' ';
    cout<<endl;
    for(auto i: ili)
        cout<<i<<' ';
    cout<<endl;
    vector<int>::iterator it1 = ivec.begin();
    list<int>::iterator lit1 = ili.begin(),lit2 = ili.end();

    while(it1 != ivec.end()){
        if (*it1 % 2 ) {
            it1 = ivec.erase(it1);
            ++lit1;
        }
        else {
            lit1 = ili.erase(lit1);
            ++it1;

        }
    }

练习9.27 编写函数,查找并删除forward_list<int>中的奇数元素。

forward_list<int> fil = {1,2,3,4,5,6,7,8,9};
     forward_list<int>::iterator prev = fil.before_begin(),curr = fil.begin();
     while(curr != fil.end()){
         if (*curr % 2 == 1){
             curr = fil.erase_after(prev);//删除prev指向的下一个元素,并将prev将要指向的下一个元素指向curr
         }else{
             prev = curr;
             ++curr;
         }
     }

练习9.28 编写函数,接受一个forward_list<string>和两个string共三个参数。函数应在链表中查找第一个string,并将第二个string插入到紧接着第一个string之后的位置。若第一个string未在链表中,则将第二个string插入到链表末尾。

void te(forward_list<string> &fls, string const &s1, string const &s2){
     forward_list<string>::iterator curr = fls.begin(), prev = fls.before_begin();
    while(curr != fls.end()){
        if(*curr == s1){
            fls.insert_after(curr,s2);
            return;
        }
        prev = curr++;
    }
    fls.insert_after(prev, s2);
 }

练习9.29 假定vec包含25个元素,那么vec.resize(100)会做什么?如果接下来调用vec.resize(10)会做什么?

vec.resize(100) // 对vec进行扩充,扩充到100个,添加了75个值初始化的元素。

vec.resize(10)//舍弃vec靠后的90个元素。

练习9.31 第316页中删除偶数值元素并复制奇数值元素的程序不能用于list或forward_list。为什么?修改程序,使之也能用于这些类型。

auto remove_evens_and_double_odds(list<int>& data)
{
    for(auto cur = data.begin(); cur != data.end();)
        if (*cur & 0x1)
            cur = data.insert(cur, *cur), advance(cur, 2);
        else
            cur = data.erase(cur);
}
auto remove_evens_and_double_odds(forward_list<int>& data)
{
    for(auto cur = data.begin(), prv = data.before_begin(); cur != data.end();)
        if (*cur & 0x1)
            cur = data.insert_after(prv, *cur),
            advance(cur, 2),
            advance(prv, 2);
        else
            cur = data.erase_after(prv);
}

练习9.32 在第316页的程序中,向下面语句这样调用inset是否合法?如果不合法,为什么?

不合法。

“未指定参数的计算顺序。”因此,在输入函数insert后,iter可能是其原始值或原始值+1,甚至是任何其他值,这取决于编译器的实现方式。

练习9.33 在本节的最后一个例子中,如果不将insert的结果赋予begin,将会发生什么?编写程序,去掉赋值语句,验证你的答案。

会死循环。

练习9.34 假定vi是一个保存int的容器,其中有偶数值也有奇数值,分析下面循环的行为,然后编写程序来验证你的分析是否正确。

      vector<int> vi = {1,2,3,4,5,6,7};
      auto iter = vi.begin();
      while(iter != vi.end()){
          if(*iter % 2) {
              iter = vi.insert(iter, *iter);
              ++iter;
          }
          ++iter;
      }
    for (auto i: vi) {
        cout<<i<<' ';
    }

之前的那个循环遇到奇数,止步不前,一直在循环,从而跳不出循环。

练习9.35 解释一个vector的capacity和size有何区别。

capacity是指在不重新分配内存的前提下,它最多可以保存多少元素。size是指已经保存的元素数目。

练习9.36 一个容器的capacity可能小于它的size吗?

capacity大于等于size

练习9.37 为什么list或者array没有capacity成员函数?

list是链表,所以每次增加元素时,都会增加相应的内存,array大小固定,不能插入元素,所以size就是array的capacity

练习9.38:编写程序,探究在你的标准库中,vector是如何增长的。

      vector<int> vi;
      cout<<"vi.size() = "<<vi.size()<<endl;
      cout<<"vi.capacity = "<<vi.capacity()<<endl;
      vi = {1,2,3,4,5,6,7};
      cout<<"vi.size() = "<<vi.size()<<endl;
      cout<<"vi.capacity = "<<vi.capacity()<<endl;
    for (int i = 1; i < 20; ++i) {
        vi.push_back(i);
        cout<<"vi.size() = "<<vi.size()<<endl;
        cout<<"vi.capacity = "<<vi.capacity()<<endl;
    }

容量是成倍增加的。但是在刚开始的时候,size和capacity是一样的。

练习9.39 解释下面的程序片段做了什么:

vector<string> svec;
sevc.reserve(1024);
string word;
while(cin>>word)
	svec.push_back(word);
sevc.resize(svec.size()+svec.size()/2);

开辟一个1024的空间,然后不断往容器里塞东西,等到不塞了,或者是超出容量了,就结束,重新分配一下空间。

练习9.41 编写程序,从一个vector< char >初始化为string

     vector<char>  c = {'i','o'};
     string s(c.begin(),c.end());

练习9.42 假定你希望每次读取一个字符存入一个string中,而且知道最少需要读取100个字符,应该如何提高程序性能?

先reverse 100个空间,然后再一个一个的输入。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值