练习9.1:考察使用哪种顺序容器
(a)list,当需要在容器中任意位置执行插入/删除操作时,用list最好
(b)deque,当需要在头部插入/删除元素,不需要在容器中间任意位置插入/删除元素时,用deque最好
(c)vector,当不需要在头部/任意位置插入/删除元素的情况下,用vector最好
练习9.2:考察对容器可以保存的元素类型的限制
list<deque<int>>lst1;
list<deque<int> >lst2; //在编译器较旧版本中的书写方式
练习9.3:考察迭代器范围的条件
它们指向同一个容器中的元素(包括尾元素的下一个位置)
end的位置不在begin之前(可以通过反复递增使得begin到达end)
练习9.4:考察通过迭代器+循环处理一个元素范围
1 bool find(vector<int>::iterator begin,vector<int>::iterator end,int value) 2 { 3 //写法1: 4 while ( begin!=end ) 5 { 6 if ( *begin==value ) return true; 7 ++begin; 8 } 9 //写法2: 10 for ( auto iter=begin;iter!=end;++iter ) 11 { 12 if ( *iter==value ) return true; 13 } 14 return false; 15 }
练习9.4
练习9.5:考察同上(当未找到定值时返回尾元素之后的那个位置)
1 vector<int>::iterator find(vector<int>::iterator begin,vector<int>::iterator end,int value) 2 { 3 //写法1: 4 while ( begin!=end ) 5 { 6 if ( *begin==value ) return begin; 7 ++begin; 8 } 9 //写法2: 10 for ( auto iter=begin;iter!=end;++iter ) 11 { 12 if ( *iter==value ) return iter; 13 } 14 return end; 15 }
练习9.5
练习9.6:考察迭代器支持的操作
两个迭代器只能判断是否相等,不能比较大小
1 list<int>lst1; 2 list<int>::iterator iter1=lst1.begin(),lter2=lst1.end(); 3 while ( iter1!=lter2 ) /*……*/
练习9.6
练习9.7:考察容器类型成员中的类型别名的使用对象
size_type得到容器大小
练习9.8:考察同上
读取string的list中的元素,使用const_iterator //只读不写
写入list,使用iterator
练习9.9:考察相似迭代器的区别
begin返回容器的iterator类型
cbegin返回容器的const_iterator类型
练习9.10:考察迭代器的类型
在gcc4.8下这段代码是错误的,因为it1和it2的类型是不一样的
正确的写法应该是
1 auto it1 = v1.begin(); 2 auto it2 = v2.begin(), it3 = v1.cbegin(), it4 = v2.cbegin();
即:只有it1是iterator,剩下对象的类型都是const_iterator
练习9.11:考察vector的创建和初始化
1 vector<int>vec1; //不包含值,容器为空 2 vector<int>vec2{1,2,3}; //包含三个值,分别为1,2,3 3 vector<int>vec3={1,2,3}; //包含三个值,分别为1,2,3 4 vector<int>vec4(vec3); //包含三个值,分别为1,2,3 5 vector<int>vec5(vec4.begin(),vec4.end()); //包含三个值,分别为1,2,3 6 vector<int>vec6(3); //包含三个值,均为0 7 vector<int>vec7(3,1); //包含三个值,均为1
练习9.11
练习9.12:考察初始化时传容器和传两个迭代器(范围)的差别
传容器:要求两个容器的容器类型和元素类型必须相同,同时得到新容器中元素的范围和老容器中元素的范围相同(整个拷贝)
传两个迭代器(范围):不要求容器类型相同,同时只要能将拷贝的元素转换为要初始化的容器的类型就可以(即新容器和老容器中的元素类型也可以不同),同时可以拷贝容器的子序列(不一定是整个容器)
练习9.13:考察容器的拷贝初始化
1 list<int>lst1; 2 vector<double>vec1(lst1.begin(),lst1.end()); 3 vector<int>vec2; 4 vector<double>vec3(vec2.begin(),vec2.end());
练习9.13
练习9.14:考察容器的赋值运算(assign)
1 list<const char*>lst; 2 vector<string>vec; 3 vec.assign(lst.cbegin(),lst.cend());
练习9.14
练习9.15:考察相同容器的大小比较
1 vector<int>vec1(3,1); 2 vector<int>vec2(3,2); 3 if ( vec1==vec2 ) cout<<"vec1==vec2"<<endl; 4 else cout<<"vec1!=vec2"<<endl;
练习9.15
练习9.16:考察不同容器的大小比较(先统一容器再进行比较)
1 vector<int>vec1(3,1); 2 list<int>lst1(3,2); 3 vector<int>vec2(lst1.begin(),lst1.end()); 4 if ( vec1==vec2 ) cout<<"vec1==lst1"<<endl; 5 else cout<<"vec1!=lst1"<<endl;
练习9.16
练习9.17:考察容器比较的限制
c1和c2必须是相同类型的容器,且必须保存相同类型的元素
同时且保存的元素必须支持条件运算符的比较
练习9.18:考察deque的push_back操作
1 deque<string>container; 2 string word; 3 while ( cin>>word ) container.push_back(word); 4 for ( auto iter=container.cbegin();iter!=container.cend();++iter ) cout<<*iter<<endl;
练习9.18
练习9.19:考察list的push_back操作及其和dequepush_back操作的不同
list、vector和deque的push_back操作类似,只需要改变一下类型名即可
1 list<string>container; 2 string word; 3 while ( cin>>word ) container.push_back(word); 4 for ( auto iter=container.cbegin();iter!=container.cend();++iter ) cout<<*iter<<endl;
练习9.19
练习9.20:考察访问list和向deque中添加元素
1 list<int>lst{1,2,3,4}; 2 deque<int>odd; 3 deque<int>even; 4 for ( auto i:lst ) 5 { 6 if ( i&1 ) odd.push_back(i); 7 else even.push_back(i); 8 }
练习9.20
练习9.21:考察为什么通过insert的返回值插入这个循环和push_front()等价
1 vector<string>vec; 2 auto iter=vec.begin(); 3 string word; 4 while ( cin>>word ) iter=vec.insert(iter,word);
练习9.21
刚开始string被添加到begin的位置,因为insert的返回值指向第一个新加入的元素的迭代器(而新加入的元素加在原来容器中begin所在的元素的前一位置,即新加入的元素变成了当前容器的begin),所以insert的返回值是当前容器的begin,每次都将重复这样的操作,即每次都往容器头部加入元素。
练习9.22:考察容器添加元素对迭代器的影响
错误:(a)循环将一直进行下次,因为iter永远无法等于mid
(b)添加元素会使mid这个迭代器失效
修改:在添加元素的过程中不断更新中间迭代器mid、当前迭代器iter和容器大小
1 vector<int>iv{1,1,1,2,3,4}; 2 int cursor=iv.size()/2; 3 int some_value=1; 4 auto iter=iv.begin(); 5 auto mid=iv.begin()+cursor; 6 while ( iter!=mid ) 7 { 8 if ( *iter==some_value ) 9 { 10 iv.insert(iter,2*some_value); 11 ++iter; 12 ++cursor; 13 mid=iv.begin()+cursor; 14 } 15 }
练习9.22
练习9.23:考察当容器中只有一个元素时,访问首元素和尾元素的结果
val==val2==val3==val4
练习9.24:考察使用不同的方式访问vector中的第一个元素,以及当容器为空时的访问结果
1 vector<int>vec; 2 vec.at(0); 3 vec[0]; 4 vec.front(); 5 *(vec.begin());
练习9.24
容器为空时,访问容器中的元素会产生未定义行为
练习9.25:考察删除多个元素
当elem1==elem2(==尾后迭代器)时,没有事情发生
当elem1!=尾后迭代器&&elem2==尾后迭代器时,删除容器中从elem1所在位置的元素往后所有的元素(包括elem1所在位置的元素)
练习9.26:考察从容器内部删除元素
1 int ia[]={0,1,1,2,3,5,8,13,21,55,89}; 2 vector<int>vec(ia,end(ia)); 3 list<int>lst(vec.begin(),vec.end()); 4 auto iter1=vec.begin(); 5 while ( iter1!=vec.end() ) 6 { 7 if ( (*iter1)&1 ) ++iter1; 8 else iter1=vec.erase(iter1); 9 } 10 auto iter2=lst.begin(); 11 while ( iter2!=lst.end() ) 12 { 13 if ( (*iter2)&1 ) iter2=lst.erase(iter2); 14 else ++iter2; 15 } 16 for ( auto i:vec ) cout<<i<<endl; 17 for ( auto i:lst ) cout<<i<<endl;
练习9.26
练习9.27:考察从forward_list中删除元素
1 forward_list<int>flst={0,1,2,3,4,5,6,7,8,9}; 2 auto prev=flst.before_begin(); 3 auto curr=flst.begin(); 4 while ( curr!=flst.end() ) 5 { 6 if ( (*curr)&1 ) curr=flst.erase_after(prev); 7 else 8 { 9 prev=curr; 10 ++curr; 11 } 12 } 13 for ( auto i:flst ) cout<<i<<endl;
练习9.27
练习9.28:考察往forward_list中添加元素
1 void find_and_insert(forward_list<string>& list,const string& to_find,const string& to_add) 2 { 3 auto prev=list.before_begin(); 4 bool change=false; 5 for ( auto curr=list.begin();curr!=list.end();prev=curr++ ) 6 { 7 if ( (*curr)==to_find ) 8 { 9 curr=list.insert_after(curr,to_add); 10 change=true; 11 } 12 } 13 if ( !change ) list.insert_after(prev,to_add); 14 }
练习9.28
练习9.29:考察resize的用法
vec.resize(100)会往rec中再添加75个元素,添加元素的值均为0
vec.resize(10)会使得rec中删除90个元素只保留下前10个元素
练习9.30:考察resize对容器初始化的影响
当元素的类型是类时,同时类的构造函数没有提供初始值时不能接受单个参数的resize
练习9.31:考察vector、list和forward_list迭代器操作的不同
list的迭代器没有+=2这样的操作,改成advance(iter,2),和+=2等价
1 list<int>vi={0,1,2,3,4,5,6,7,8,9}; 2 auto iter=vi.begin(); 3 while ( iter!=vi.end() ) 4 { 5 if ( (*iter)&1 ) 6 { 7 iter=vi.insert(iter,*iter); 8 advance(iter,2); 9 } 10 else iter=vi.erase(iter); 11 } 12 for ( auto i:vi ) cout<<i<<endl;
list
forword_list中重点注意两个迭代器位置的变化
1 forward_list<int>vi={0,1,2,3,4,5,6,7,8,9}; 2 auto prev=vi.before_begin(); 3 auto iter=vi.begin(); 4 while ( iter!=vi.end() ) 5 { 6 if ( (*iter)&1 ) 7 { 8 iter=vi.insert_after(prev,*iter); 9 advance(iter,2); 10 advance(prev,2); 11 } 12 else iter=vi.erase_after(prev); 13 } 14 for ( auto i:vi ) cout<<i<<endl;
forward_list
练习9.32:考察程序规范
不合法,当执行完insert后,iter进行的操作取决于编译器是不确定的。更详细的讨论请看:https://github.com/Mooophy/Cpp-Primer/issues/125
练习9.33:考察insert的返回值(返回插入的第一个新添加的元素)
insert使得vector的存储空间被重新分配,导致迭代器失效,会造成程序崩溃
练习9.34:考察insert的返回值
会造成无限循环,当访问的一个奇数时,会无限访问该奇数,因为程序遇到奇数会在奇数前添加一个元素,同时迭代器指向该奇数的前一个元素,当迭代器++时又是该奇数
1 #include<iostream> 2 #include<vector> 3 using namespace std; 4 5 int main() 6 { 7 vector<int>vi={0,1,2,3,4,5,6,7,8,9}; 8 auto iter=vi.begin(); 9 while ( iter!=vi.end() ) 10 { 11 if ( (*iter)&1 ) 12 { 13 iter=vi.insert(iter,*iter); 14 ++iter; 15 } 16 ++iter; 17 } 18 for ( auto i:vi ) cout<<i<<endl; 19 }
练习9.34
原文地址:https://www.cnblogs.com/HDUjackyan/p/9547263.html