赞
踩
9.1:对于下面的程序任务,vector,deque,和list那种容器最为适合?解释你的选择的理由。如果没有哪一种容器优于其他容器,也请解释理由。
(a) 读取固定数量的的单词,将他们按照字典序插入到容器中,我们将下一章看到,关联容器更加适合这个问题。
答:vector更好,vector支持随机访问,操作性更大
(b)读取未知数目的单词,总是将新单词插入到末尾。删除操作在末尾进行。
答:list更好,因为只针对删除的话链表的删除的效率还是十分之高的
(c ) 从一个文件读取未知数量的整数。将这些数排序,然后将他们打印到标准输出
答:vector更好,vector进行排序的效率较其他两种效率高
官方解答:
a:按字典序插入到容器中意味着进入插入排序操作,从而需要在容器内部进入插入排序工作,vector在尾部之外的插入和删除元素很慢,deque在头尾之外的位置删除和插入排序很慢,而list则适用于任何情况插入。但是如果是先装入然后利用sort排序,利用vector也可以。
b:由于需要频繁进行插入删除操作,于是选择deque或者list,如果需要频繁的随机访问,则为deque
c:由于整数占用空降很小,而且排序需要频繁随机访问,选择vector
9.2:定义一个list对象,其元素类型为int的deque。
答:
list<deque<int>> mylist;
9.3构成迭代器范围的迭代器有何限制?
答:两个迭代器begin和end必须指向同一个容器中的元素或者是容器最后一个元素之后的位置,我们可以通过反复递增begin来达到end,end不在begin之前
9.4:编写程序,接受一对指向vector< int >的迭代器和一个int值,在两个迭代器指定的范围中查找给定的值,返回一个布尔值来指出是否找到
答:
#include <cstdio> #include <iostream> #include<vector> using namespace std; bool my_find(vector<int>::iterator first,vector<int>::iterator last,int num){ while(first!=last){ if(*first==num) return true; first++; } return false; } int main() { //测试 vector<int> test = {1, 2, 3, 4}; cout << my_find(test.begin(), test.end(), 3) << endl; getchar(); return 0; }
9.5:重写上一题的程序,返回一个迭代器指向找到的元素,注意,程序
答:
#include <cstdio> #include <iostream> #include<vector> using namespace std; vector<int>::iterator my_find(vector<int>::iterator first,vector<int>::iterator last,int num){ while(first!=last){ if(*first==num) return first; first++; } return last; } int main() { //测试 vector<int> test = {1, 2, 3, 4}; cout << *my_find(test.begin(), test.end(), 4) << endl; getchar(); return 0; }
9.6:下面的程序有何问题?你应该如何修改它?
list<int>lst1;
list<int>::iterator iter1=lst1.begin(),iter2=lst2.end();
while(iter1<iter2)/*...*/
答:
迭代器不支持>和<,可以修改成while(iter1!=iter2)
9.7:为了索引int的vector中元素,应该使用什么类型。
答:iterator
9.8:为了读取string的list中的元素,应该使用什么类型?如果写入list,又该使用什么类型?
答:value_type表示元素类型,可以读取、reference表示引用类型,可以写入
9.9:begin和cbegin有啥区别?
答:begin是普通的迭代器,可以改变容器元素,而cbegin是const begin,不可以改变容器元素
9.10:下面的4个对象分别是什么类型?
vector<int>vi;
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>ans;//空
vector<int>ans(10);//10个值,每个值为0
vector<int>ans={1,2,3,4};//1,2,3,4
vector<int>ans(10,1);//10个值,每个值为1
vector<int>ans(ans1);//拷贝ans1中的元素
vector<int>ans(ans1.begin()+1,ans1.end());//初始化为两个迭代器指定范围的元素
9.12:对于接受一个容器创建其拷贝的构造函数,和接受两个迭代器创建拷贝的构造函数,解释它们的不同。
答:迭代器所拷贝的是其范围内的元素,而接受一个容器创建是全部元素
9.13:如何从一个list< int >初始化为一个vector< double>,从一个vector< int >又该如何创建?编写代码验证你的解答。
答:容器类型不同,所以采用范围初始化,vector< int > dvec(list.begin(),list.end()),从vector转化为vector< double >可采用容器初始化vector< double >devc=list
9.14:将一个list中的char*指针(指向c风格字符串)元素赋值给vector中的string
答:由于char*类型不同于string但是可以转换成stirng所以可以利用范围赋值方式
9.15:编写程序,判断两个vector< int >是否相等
答:类型和容器都相同,所以可以使用等于判断符
int main()
{
//测试
vector<int> test = {1, 2, 3, 4};
vector<int> test1 = {1, 2, 3, 4};
//cout << test == test1 << endl;
int ret = test == test1;
cout << ret << endl;
getchar();
return 0;
}
9.16:重写上一段的程序,比较一个list< int >中的元素和一个vector< int >中的元素
答:由于容器不同,所以需要使用范围内赋值方式,之后再通过等号关系符来进行比较
int main()
{
//测试
vector<int> test = {1, 2, 3, 4};
vector<int> test1 = {1, 2, 3, 4};
list<int> test2={1,2,3,4,5,6};
vector<int> ans(test2.begin(), test2.end());
int ret = ans == test1;
cout << ret << endl;
getchar();
return 0;
}
9.17:假如c1和c2是两个容器,下面的比较操作有何限制(如果有的话)
if(c1<c2)
答:需要是同类型的容器,相同类型的元素,能支持<运算符
9.18:编写程序,从标准输入读取string序列,存入一个deque中,编写一个循环,用迭代器打印deque中的元素。
答:
int main()
{
//测试
string line;
deque<string> ans;//双端队列
while(getline(cin,line)){
ans.push_back(line);
}
for(auto &ans1:ans){
cout << ans1 << " ";
}
getchar();
return 0;
}
9.19:重写上面的程序,用list代替deque,列出程序中需要做出哪些改变。
答:
int main()
{
//测试
string line;
list<string> ans;//双链表
while(getline(cin,line)){
ans.push_back(line);
}
for(auto &ans1:ans){
cout << ans1 << " ";
}
getchar();
return 0;
}
9.20:编写程序,从一个list< int >拷贝元素到两个deque中。值为偶数的所有元素都拷贝到一个deque中,而奇数值元素都拷贝到另一个deque中
答:
int main()
{
//测试
list<int> list1 = {1, 2, 3, 4, 5};
deque<int> d1, d2;
for(auto &ans:list1){
if(ans%2){
d1.push_back(ans);
}else{
d2.push_back(ans);
}
}
getchar();
return 0;
}
9.21:如果我们将第308页中使用insert返回值将元素添加到list中的循环改写为将元素插入到vector中,分析循环将如何工作
答:其循环就是当iter永远指向第一个元素,元素为零是则为空,然后造成其插入后元素的顺序与输入顺序相反
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);
}
答:迭代器没有增加,不会到中间节点,然后对于vector,deque,string容器直接加入是会使迭代器,指针,引用失效
int main() { //测试 vector<int> iv = {1, 2, 3, 4}; int some_val = 2; int this_size = iv.size(); int count = 0; vector<int>::iterator iter = iv.begin(), mid = iv.begin() + this_size / 2+count; while (iter != iv.begin() + this_size / 2+count) { if (*iter == some_val){ iter=iv.insert(iter, 2 * some_val); iter++; iter++; count++; }else{ iter++; } } for(auto &ans:iv){ cout << ans << " "; } getchar(); getchar(); return 0; }
9.23:在本节第一个程序(309页),若c.size()为1,则val1,val2,val3,val4值为多少?
答:值都是第一个元素
9.24:编写程序,分别使用at,下标运算符、front何begin提取一个vector中的第一个元素。在一个空的vector上测试你的程序。
答:
程序会异常终止,因为使用at运算,超出范围返回会抛出out_of_range异常
int main()
{
vector<int> test;
cout << test.at(0) << endl;
cout << test[0] << endl;
cout << test.front() << endl;
cout << *test.begin() << endl;
getchar();
getchar();
return 0;
}
9.25:对于312页中删除一个范围内的元素的程序,如果elem1与elem2相等会发生什么,如果elem2是尾后迭代器,或者elem1和elem2皆为尾后迭代器,又会发生什么
答:则一个元素也删除不了
9.26:使用下面代码定义的ia,将ia拷贝到一个vector和一个list中。使用单迭代版本的erase从list中删除元素,从vector中删除偶数元素。
答:
#include <cstdio> #include <iostream> #include<vector> #include<string> #include<deque> #include<list> using namespace std; vector<int>::iterator my_find(vector<int>::iterator first,vector<int>::iterator last,int num){ while(first!=last){ if(*first==num) return first; first++; } return last; } int main() { int ia[] = {0, 1, 1, 2, 3, 5, 8, 13, 21, 55, 89}; vector<int> ivec; for(auto &val:ia){ ivec.emplace_back(val); } list<int> list1(ivec.begin(), ivec.end()); for (auto iv = ivec.begin();iv!=ivec.end();){ if((*iv)&1) ; else{ iv=ivec.erase(iv); continue; } iv++; } for (auto iv = list1.begin();iv!=list1.end();){ if((*iv)&1){ iv=list1.erase(iv); continue; } iv++; } for(auto &ans:list1){ cout << ans << " "; } for(auto &ans:ivec){ cout << ans << " "; } getchar(); getchar(); return 0; }
9.27:编写程序,查找程序并删除forward_list< int>中的奇数元素
答:
#include <cstdio> #include <iostream> #include<vector> #include<string> #include<deque> #include<list> #include<forward_list> using namespace std; vector<int>::iterator my_find(vector<int>::iterator first,vector<int>::iterator last,int num){ while(first!=last){ if(*first==num) return first; first++; } return last; } int main() { forward_list<int> list1 = {1, 2, 3, 4, 5, 6}; auto pre = list1.before_begin(); auto curr = list1.begin(); while(curr!=list1.end()){ if(*curr&1){ curr = list1.erase_after(pre); }else{ pre = curr; ++curr; } } for(auto &ans:list1){ cout << ans << " "; } getchar(); getchar(); return 0; }
9.28:编写函数,接受一个forward_list< string >和两个string共三个参数。函数应该在链表中查找一个string,并将第二个string插入到紧接着第一个string之后的位置。若第一个string未在链表中,则将第二个string插入到来链表中
答:
#include <cstdio> #include <iostream> #include<vector> #include<string> #include<deque> #include<list> #include<forward_list> using namespace std; void my_insert(forward_list<string>&l1,string s1,string s2){ for (auto curr = l1.begin(); curr != l1.end();++curr){ if(*curr==s1){ l1.insert_after(curr, s2); return; } } } int main() { forward_list<string> l1 = {"1", "2", "3", "4"}; my_insert(l1, "3", "5"); for(auto &ans:l1){ cout << ans << " "; } getchar(); getchar(); return 0; }
9.29:假定vec包含25个元素,那么vec.resize(100)会做什么?接下来调用vec.resize(10)会发生什么。
答:会将其元素扩到100个元素,然后其余的75个元素为0,接下来会发生截断,即只剩下前10个元素
9.30:接受单个元素的resize版本对元素类型有什么限制(如果有的话)
答:如果元素是类类型,则单参数resize版本要求该类型必须提供一个默认构造函数
9.31:第316页中删除偶数值并复制奇数值元素的程序不能用于list或者forward_list。为什么?修改程序,使之能用于这些程序。
答:由于list和forward_list是链表,所以如果要插入值,必须要其前驱,并且没有对于链表没有insert函数
#include <cstdio> #include <iostream> #include<vector> #include<string> #include<deque> #include<list> #include<forward_list> using namespace std; int main() { forward_list<int> l1 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; auto pre = l1.before_begin(); auto curr = l1.begin(); while(curr!=l1.end()){ if(*curr&1){ curr = l1.insert_after(curr, *curr); pre = curr; curr++; }else{ curr = l1.erase_after(pre); } } for(auto &ans:l1){ cout << ans << " "; } getchar(); getchar(); return 0; }
9.32:在第316页中程序中,向下面语句这样调用insert是否合法,如果不合法,为什么?
iter=vi.insert(iter,*iter++)
答:很多编译器对实参求值,向形参传递的处理顺序是由右向左的。这意味这编译器在在编译上述代码时,首先对*iter++求值,传递的第一个参数的迭代器指向的是错误位置。
9.33:在本节的最后一个例子中,如果不将insert的结果赋予begin,将会发生什么?编写程序,去掉赋值语句,验证你的答案。
答:插入操作会导致迭代器失效,所以必须赋值
9.34:假定vi是一个保存int的容器,其中有偶数值也有奇数值,分析下面循环的行为,然后编写程序来验证你的分析是否正确。
iter=vi.begin();
while(iter!=vi.end())
if(*iter%2)
iter=vi.insert(iter,*iter);
++iter;
答:
#include <cstdio> #include <iostream> #include<vector> #include<string> #include<deque> #include<list> #include<forward_list> using namespace std; 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; cout << *iter << " "; } for(auto &ans:vi){ cout << ans << " "; } getchar(); getchar(); return 0; }
9.35:解释一个vector的capacity和size有何区别
答:capacity代表分配给容器内存的元素个数,而size代表现在容器中元素的个数
9.36:一个容器的capacity可能小于它的size吗?
答:基本上不可能
9.37:为什么list或者array没有capasity成员函数?
答:array容器是因为其大小已经固定,不可增加和减少,而list是由于是链表,每增加一个元素就会增加对应大小的内存
9.38:编写程序,探究在你的标准库中,vector是如何增长的。
答:
#include <cstdio> #include <iostream> #include<vector> #include<string> #include<deque> #include<list> #include<forward_list> using namespace std; int main() { vector<int> vi; int s, c; for(s=vi.size(),c=vi.capacity();s<=c;s++){ vi.push_back(1); } cout << "空间:" << vi.capacity() << "元素数" << vi.size() << endl; for(s=vi.size(),c=vi.capacity();s<=c;s++){ vi.push_back(1); } cout << "空间:" << vi.capacity() << "元素数" << vi.size() << endl; for(s=vi.size(),c=vi.capacity();s<=c;s++){ vi.push_back(1); } cout << "空间:" << vi.capacity() << "元素数" << vi.size() << endl; for(s=vi.size(),c=vi.capacity();s<=c;s++){ vi.push_back(1); } cout << "空间:" << vi.capacity() << "元素数" << vi.size() << endl; getchar(); getchar(); return 0; }
9.39:解释下面的程序片段做了什么:
vector<string>svec;
sevc.reserve(1024);
string word;
while(cin>>word)
svec.push_back(word);
sevc.resize(svec.size()+svec.size()/2);
答:将输入的字符串加入容器中,之后等结束输入或者超出其容器的范围后再重置容器的大小
9.40:如果上一题中的程序读入256个单词,在resize之后容器的capacity可能是多少?如果读入了512个单词,1000个或者是1048个单词呢?
答:256是384,512是768,1000是2048,1048是2048
9.41:编写程序,从一个vector< char >初始化为string
答:
vector<char> ivec = {'1', '2', '3', '4'};
string s(ivec.begin(), ivec.end());
9.42:假定你需要每次读取一个字符存入一个string中,而且知道最少需要读取100个字符,应该如何提高性能。
答:可以先用reserve为其预先分配100个空间,然后利用push_back来加入字符
9.43:编写一个函数,接受三个string参数s,oldVal和newVal。使用迭代器以及inset和erase函数将s中所有oldVal替换成newVal.测试你的程序,用它替换通用的简写形式,如,将"tho"替换成"though",将"thru"替换成"through"
答:
#include<string> #include<vector> #include<iostream> using namespace std; void my_replace(string &s,string &oldVal,string &newVal){ int count = 0; for (auto begin = s.begin(); begin != s.end();begin++,count++){ if(*begin==oldVal[0]){ auto a = begin; int k = 0; bool flag = true; while(a!=s.end()&&k<oldVal.size()){ if(*a!=oldVal[k]){ flag = false; } ++a; ++k; } if(flag){ s.erase(count, k); s.insert(count, newVal); } begin = a; } } } int main() { string a = "th i sd "; string b = "though"; string c = "th"; my_replace(a, c, b); cout << a << endl; getchar(); getchar(); return 0; }
9.44:重写上一题的程序,这次使用一个下标和replace
答;
#include<string> #include<vector> #include<iostream> using namespace std; void my_replace(string &s,string &oldVal,string &newVal){ int count = 0; for (int i=0; i<s.size();i++,count++){ if(s[i]==oldVal[0]){ int k = 0; int a = i; bool flag = true; while(a<s.size()&&k<oldVal.size()){ if(s[a]!=oldVal[k]){ flag = false; } ++a; ++k; } if(flag){ s.replace(i, k, newVal); } } } } int main() { string a = "th i sd "; string b = "though"; string c = "th"; my_replace(a, c, b); cout << a << endl; getchar(); getchar(); return 0; }
9.45:编写一个函数,接受一个表示名字的string参数和两个表示前缀如(“Mr")和后缀如(“Jr.")的字符串。使用迭代器及insert和append函数将前缀和后缀添加到给定的名字中,将生成新的string返回。
答;
string my_add(string &name,string prefix,string tailfix){
name.insert(0, prefix);
name.append(tailfix);
return name;
}
9.46:重写上一题的函数,这次使用的位置和长度来管理,并且只使用insert
答:
void name_string(string &name,const string &prefix,const string &suffix){
name.insert(0," ");
name.insert(0,prefix);
name.insert(name.size()," ");
name.insert(name.size(),suffix);
}
int main(){
string s="James";
name_string(s,"Mr.","II");
cout<<s<<endl;
return 0;
}
9.47:首先查找stirng”ab2c3d7r4e6"中的每个数字字符,然后查找字母字符,编写两个版本的程序,第一要使用find_first_of,第二个要使用find_first_not_of
答:
//主要函数
void find_char(string &s,const string &word ){
string::size_type pos=0;
while((pos=s.find_first_of(word,pos))!=string::npos){
cout << "位置:" << pos << "值:" << s[pos] << endl;
++pos;
}
}
void find_char2(string&s,const string &word){
string ::size_type pos = 0;
while((pos=s.find_first_not_of(word,pos))!=string::npos){
cout << "位置:" << pos << "值:" << s[pos] << endl;
++pos;
}
}
9.48:假如name和numbers的定义如325页所示numbers.find(name)返回结果如何
答:由于找不到,所以返回为npos
9.49:如果一个字母延申到中线之上,如d或f则称其为有上出头部分如果一个字母延伸到中线一下,如p或g则称为下出头部分,编写程序读入一个单词文件,输出最长的不包含上出头以及下出头部分的单词
答:
void find_longest_string(ifstream &in){ string word, longest_word; int max_length = 0; while(in>>word){ if(word.find_first_of("bdfghjklpqty")!=string::npos) continue; if(word.size()>max_length){ max_length = word.size(); longest_word = word; } } cout << "最长不上头不下头单词为:" << longest_word << endl; return; } int main() { string file = "D:\\data.txt"; ifstream input(file); find_longest_string(input); getchar(); getchar(); return 0; }
9.50:编写程序处理一个vector< string >,其元素表示整数值。计算vector中所有元素之和。修改程序,使之计算表示浮点数值的string之和
答:
int main()
{
vector<string> ivec = {"1", "2", "3", "4"};
double sum = 0;
for(auto &ans:ivec){
sum += stod(ans);//转换成浮点数
}
cout << sum << endl;
getchar();
getchar();
return 0;
}
9.51:设计一个类,它有三个unsigned成员,分别表示年月日,为其编写构造函数,接受一个表示日期的string参数。你的构造函数应该能够处理不同的数据格式。如January 1,1900,1/1/1900 Jan 1 1900等
9.52:使用stack处理括号化的表达式,当你看到一个左括号,将其记录下来,当你在左括号之后看到一个右括号,从stack中pop对象,直到遇到左括号,将左括号页一起弹出栈。然后将一个值(括号内的运算结果)push到栈中,表示一个括号内的表达式已经处理完毕,被其运算结果所代替。
答:对于这两题的难度都比较大,是一次综合的运用,我就单独写上去放到我的c/c++专栏上,并且尽量让其结构比较完整。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。