赞
踩
【C++ Primer】第三章 字符串、向量和数组 (练习)
对于下面的程序任务,vector、deque 和 list 哪种容器最为适合?解释你的选择的理由。如果没有哪一种容器优于其他容器,也请解释理由。
- (a) 读取固定数量的单词,将它们按字典序插入到容器中。我们将在下一章中看到,关联容器更适合这个问题。
- (b) 读取未知数量的单词,总是将单词插入到末尾。删除操作在头部进行。
- (c) 从一个文件读取未知数量的整数。将这些数排序,然后将它们打印到标准输出。
解答
定义一个 list 对象,其元素类型是 int 的 deque。
解答
- #include <iostream>
- #include <deque>
- #include <list>
- using namespace std;
-
- int main()
- {
- list<deque<int>> obj;
- return 0;
- }
构成迭代器范围的迭代器有何限制?
解答
编写函数,接受一对指向 vector<int> 的迭代器和一个 int 值。在两个迭代器指定的范围中查找给定的值,返回一个布尔值来指出是否找到。
解答
- bool find_val(vector<int>::const_iterator beg, vector<int>::const_iterator end, int val)
- {
- while(beg != end) {
- if ((*beg) == val) {
- return true;
- }
- ++beg;
- }
- return false;
- }
重写上一题的函数,返回一个迭代器指向找到的元素。注意,程序必须处理未找到给定值的情况。
解答
- // 由于需要返回迭代器, 用户可能希望修改元素, 故不再使用常量迭代器
- vector<int>::iterator find_val(vector<int>::iterator beg, vector<int>::iterator end, int val)
- {
- for( ; beg != end; ++beg) { // 改用 for 循环亦可
- if ((*beg) == val)
- return beg;
- }
- return end;
- }
下面的程序有何错误?你应该如何修改它?
list<int> lst1; list<int>::iterator iter1 = lst1.begin(), iter2 = lst1.end(); while (iter1 < iter2) /* ... */
解答
迭代器的循环条件应为:
while (iter1 != iter2) /* ... */
为了索引 int 的 vector 中的元素,应该使用什么类型?
解答
- // 既可以
- vector<int>::size_type
-
- // 也可以
- vector<int>::iterator
- vector<int>::const_iterator
为了读取 string 的 list 中的元素,应该使用什么类型?如果写入 list,又应该使用什么类型?
解答
- // 读(2种)
- list<string>::const_iterator // 常量迭代器
- list<string>::value_type
-
- // 写(2种)
- list<string>::iterator // 迭代器
- list<string>::reference
begin 和 cbegin 两个函数有什么不同?
解答
下面 4 个对象分别是什么类型?
vector<int> v1; const vector<int> v2; auto it1 = v1.begin(), it2 = v2.begin(); auto it3 = v1.cbegin(), it4 = v2.cbegin();
解答
it1 是 vector<int>::iterator 类型的,it2、it3、it4 均为 vector<int>::const_iterator 类型的。
对 6 种创建和初始化 vector 对象的方法,每一种都给出一个实例。解释每个 vector 包含什么值。
解答
- vector<int> vec; // 1 个 0
- vector<int> vec(10); // 10 个 0
- vector<int> vec(10, 1); // 10 个 1
- vector<int> vec{ 1, 2, 3 }; // 1, 2, 3
- vector<int> vec(vec2); // 拷贝 vec2 所有的元素
- vector<int> vec(vec2.begin(), vec2.end()); // 拷贝 vec2 迭代器范围内所有的元素
对于接受一个容器创建其拷贝的构造函数,和接受两个迭代器创建拷贝的构造函数,解释它们的不同。
解答
如何从一个 list<int> 初始化一个 vector<double> ?从一个 vector<int> 又该如何创建?编写代码验证你的答案。
解答
- // 由于类型不匹配, 不可以使用拷贝初始化
- // 但元素类型可以转换, 故需使用迭代器指定元素范围拷贝
- list<int> lst = {0, 1, 2, 3, 4};
- vector<double> dvec(lst.begin(), lst.end());
-
- vector<int> ivec = {5, 6, 7, 8, 9};
- vector<double> dvec2(ivec.begin(), ivec.end());
编写程序,将一个 list 中的 char * 指针 (指向 C 风格字符串) 元素赋值给一个 vector 中的 string 。
解答
- // 容器类型不同, 不能直接赋值
- // 元素类型相容, 可以采用范围辅助
- list<const char*> lst = {"hello", "world"};
- vector<string> vec;
- vec.assign(lst.begin(), lst.end());
编写程序,判定两个 vector<int> 是否相等。
解答
源程序:
- #include <iostream>
- #include <vector>
- using namespace std;
-
- int main()
- {
- vector<int> ivec = {1, 2, 3};
- vector<int> ivec1 = {1, 2, 3};
- vector<int> ivec2 = {1, 2};
- vector<int> ivec3 = {1, 2, 4};
- vector<int> ivec4 = {1, 3, 2};
-
- cout << (ivec == ivec1) << endl;
- cout << (ivec == ivec2) << endl;
- cout << (ivec == ivec3) << endl;
- cout << (ivec == ivec4) << endl;
-
- ivec1.push_back(4);
- ivec1.pop_back();
- cout << ivec1.capacity() << " " << ivec1.size() << endl;
- cout << (ivec == ivec1) << endl;
-
- return 0;
- }
输出:
- 1
- 0
- 0
- 0
- 6 3
- 1
重写上一题的程序,比较一个 list 中的元素和一个 vector 中的元素。
解答
源程序:
- #include <iostream>
- #include <vector>
- #include <list>
- using namespace std;
-
- bool isEqual(vector<int> &ivec, list<int> &ilst)
- {
- if(ivec.size() != ilst.size()) // 先比较长度
- return false;
-
- auto vbeg = ivec.cbegin();
- auto vend = ivec.cend();
- auto lbeg = ilst.cbegin();
- auto lend = ilst.cend();
-
- while((vbeg != vend) || (lbeg != lend)) { // 只写入其一也行
- if((*vbeg) != (*lbeg))
- return false;
- ++vbeg;
- ++lbeg;
- }
- return true;
- }
-
- int main()
- {
- vector<int> ivec = {1, 2, 3};
- list<int> ilst = {1, 2, 3};
- cout << isEqual(ivec, ilst) << endl;
-
- ivec.push_back(4);
- cout << isEqual(ivec, ilst) << endl;
-
- ivec.pop_back();
- ivec.pop_back();
- cout << isEqual(ivec, ilst) << endl;
-
- return 0;
- }
输出:
- 1
- 0
- 0
假定 c1 和 c2 是两个容器,下面的比较操作有何限制?
if (c1 < c2)
解答
编写程序,从标准输入读取 string 序列,存入一个 deque 中。编写一个循环,用迭代器打印 deque 中的元素。
解答
源程序:
- #include <iostream>
- #include <string>
- #include <deque>
- using namespace std;
-
- int main()
- {
- // 输入并保存元素
- deque<string> deq;
- string str;
- while(cin >> str) {
- deq.push_back(str);
- }
- // 通过常量迭代器打印元素
- for(auto iter = deq.cbegin(); iter != deq.cend(); ++iter) {
- cout << (*iter) << endl;
- }
-
- system("pause");
- return 0;
- }
输出:
- hello world my dear
- ^Z
- hello
- world
- my
- dear
重写上一题的程序,用 list 替代 deque。列出程序要做出哪些改变。
解答
编写程序,从一个 list<int> 拷贝元素到两个 deque 中。值为偶数的所有元素都拷贝到一个 deque 中,而奇数值元素都拷贝到另一个 deque 中。
解答
源程序:
- #include <iostream>
- #include <list>
- #include <deque>
- using namespace std;
-
- int main()
- {
- // 初始化容器
- list<int> lst = {0, 1, 2, 3, 4};
- deque<int> odd, even;
-
- // 通过迭代器拷贝
- auto iter = lst.cbegin();
- auto end = lst.cend();
- while(iter != end) {
- int num = *iter;
- if(num % 2 == 1) // 等价于 if(num & 1) 查看最低位, 1:奇数, 0:偶数
- odd.push_back(num);
- else
- even.push_back(num);
- ++iter;
- }
- // 等价于
- // for (auto i : lst)
- // (i & 0x1 ? odd : even).push_back(i);
-
- // 打印结果验证
- for(auto o : odd) { cout << o << " "; }
- cout << endl;
- for(auto e : even) { cout << e << " "; }
- cout << endl;
-
- system("pause");
- return 0;
- }
输出:
- 1 3
- 0 2 4
如果我们将第 308 页中使用 insert 返回值将元素添加到 list 中的循环程序改写为将元素插入到 vector 中,分析循环将如何工作。
解答
源程序:
- #include <iostream>
- #include <vector>
- using namespace std;
-
- int main()
- {
- vector<string> svec;
- string word;
- auto iter = svec.begin();
- while(cin >> word) {
- iter = svec.insert(iter, word);
- }
-
- for(auto iter = svec.cbegin(); iter != svec.end(); ++iter) {
- cout << *iter << endl;
- }
-
- system("pause");
- return 0;
- }
控制台交互:
- hello world my dear
- ^Z
- dear
- my
- world
- hello
假定 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);
解答
源程序 - 方式一:
- #include <iostream>
- #include <vector>
- using namespace std;
-
- int main()
- {
- vector<int> iv = {2, 1, 1, 2, 1};
- int some_val = 2; // 目标值
-
- vector<int>::iterator iter = iv.begin();
- int org_size = iv.size(), new_elem = 0; // 原始大小, 新元素数
-
- // 每个循环步都重新计算 mid, 保证正确指向 iv 原中央元素
- while(iter != (iv.begin() + org_size / 2 + new_elem)) {
- if(*iter == some_val) {
- iter = iv.insert(iter, 2*some_val); // iter 指向新元素
- new_elem++; // 新元素数 +1
- iter++; // 将 iter 移到新元素的下一个位置
- }
- iter++; // 将 iter 推进到旧元素的下一个位置
- }
-
- // 用 begin() 获取 vector 首元素迭代器, 遍历 vector 中的所有元素
- for(iter = iv.begin(); iter != iv.end(); iter++)
- cout << *iter << endl;
-
- system("pause");
- return 0;
- }
输出:
- 4
- 2
- 1
- 1
- 2
- 1
源程序 - 方式二:
- #include <iostream>
- #include <vector>
- using namespace std;
-
- int main()
- {
- vector<int> iv = {2, 1, 1, 2, 1};
- int some_val = 2; // 目标值
-
- vector<int>::iterator iter = iv.begin();
- int org_size = iv.size(), i = 0; // 原始大小, 循环次数
-
- // 用循环遍历控制循环次数
- while(i <= org_size / 2) {
- if(*iter == some_val) {
- iter = iv.insert(iter, 2*some_val); // iter 指向新元素
- iter++; // 将 iter 移到新元素的下一个位置
- }
- iter++; // 将 iter 推进到旧元素的下一个位置
- i++; // 循环次数 +1
- }
-
- // 用 begin() 获取 vector 首元素迭代器, 遍历 vector 中的所有元素
- for(iter = iv.begin(); iter != iv.end(); iter++)
- cout << *iter << endl;
-
- system("pause");
- return 0;
- }
输出:
- 4
- 2
- 1
- 1
- 2
- 1
在本节第一个程序中,若 c.size() 为1,则 val、val2、val3 和 val4 的值会是什么?
解答
四个变量的值会相同,均为容器中唯一元素的值。
编写程序,分别使用 at、下标运算符、front 和 begin 提取一个 vector 中的第一个元素。在一个空 vector 上测试你的程序。
解答
- #include <iostream>
- #include <vector>
- using namespace std;
-
- int main()
- {
- vector<int> ivec;
-
- cout << ivec.at(0) << endl; // terminating with uncaught exception of type std::out_of_range
- cout << ivec[0] << endl; // Segmentation fault: 11
- cout << ivec.front() << endl; // Segmentation fault: 11
- cout << *(ivec.begin()) << endl; // Segmentation fault: 11
-
- system("pause");
- return 0;
- }
对于第 312 页中删除一个范围内的元素的程序,如果 elem1 与 elem2 相等会发生什么?如果 elem2 是尾后迭代器,或者 elem1 和 elem2 皆为尾后迭代器,又会发生什么?
解答
使用下面代码定义的 ia,将 ia 拷贝到一个 vector 和一个 list 中。使用单迭代器版本的 erase 从 list 中删除奇数元素,从 vector 中删除偶数元素。
int ia[] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 55, 89 };
解答
源程序:
- #include <iostream>
- #include <vector>
- #include <list>
- using namespace std;
-
- int main()
- {
- // 基本数据
- int ia[] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 55, 89 };
- vector<int> ivec;
- list<int> ilst;
-
- // 数据拷贝
- ivec.assign(ia, ia+11);
- ilst.assign(ia, ia+11);
-
- // 删除奇数元素
- auto iiter = ivec.begin(); // 等价于 vector<int>::iterator iiter = ivec.begin();
- while(iiter != ivec.end()) {
- if((*iiter) % 2)
- iiter = ivec.erase(iiter);
- else
- ++iiter;
- }
-
- // 删除偶数元素
- for(auto liter = ilst.begin(); liter != ilst.end(); ) { // 等价于 list<int>::iterator liter = ilst.begin();
- if(!(*liter % 2))
- liter = ilst.erase(liter);
- else
- ++liter;
- }
-
- // 打印结果
- cout << "even vector: ";
- for (auto v : ivec)
- cout << v << " ";
- cout << endl;
-
- cout << "odd list: ";
- for (auto l : ilst)
- cout << l << " ";
- cout << endl;
-
- system("pause");
- return 0;
- }
输出:
- even vector: 0 2 8
- odd list: 1 1 3 5 13 21 55 89
编写程序,查找并删除 forward_list<int> 中的奇数元素。
解答
源程序:
- #include <iostream>
- #include <forward_list>
- using namespace std;
-
- int main()
- {
- // 处理
- forward_list<int> fwlst = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 55, 89 };
- forward_list<int>::iterator prev = fwlst.before_begin(); // 伪头部 - 哨兵节点
- forward_list<int>::iterator curr = fwlst.begin(); // 真头部 - 首节点
- while(curr != fwlst.end()) {
- if(*curr % 2 == 1) {
- curr = fwlst.erase_after(prev);
- }
- else {
- prev = curr;
- ++curr;
- }
- }
-
- // 打印
- cout << "even forward_list: ";
- for(auto f : fwlst)
- cout << f << " ";
- cout << endl;
-
- system("pause");
- return 0;
- }
输出:
even forward_list: 0 2 8
编写函数,接受一个 forward_list<string> 和两个 string 共三个参数。函数应在链表中查找第一个 string,并将第二个 string 插入到紧接着第一个 string 之后的位置。若第一个 string 未在链表中,则将第二个 string 插入到链表末尾。
解答
源程序:
- #include <iostream>
- #include <forward_list>
- #include <string>
- using namespace std;
-
- int main()
- {
- forward_list<string> f = {"aa", "bb", "cc", "ee"}; // 单链表
- string x = "cc", y = "dd"; // 待寻找元素, 待插入元素
- forward_list<string>::iterator prev = f.before_begin(); // 哨兵节点
- forward_list<string>::iterator curr = f.begin(); // 头节点
- while(curr != f.end()) {
- if(*curr == x) {
- f.insert_after(curr, y); // 中间位置插入插入并打印
- for(auto n : f)
- cout << n << " ";
- cout << endl;
-
- system("pasue");
- return 0;
- }
- prev = curr; // 双指针后移
- ++curr;
- }
- f.insert_after(prev, y); // 末尾位置插入元素并打印
- for(auto n : f)
- cout << n << " ";
- cout << endl;
-
- system("pause");
- return 0;
- }
输出:
- aa
- bb
- cc
- dd
- ee
假定 vec 包含 25 个元素,那么 vec.resize(100) 会做什么?如果接下来调用 vec.resize(10) 会做什么?
解答
调用 vec.resize(100) 会将 75 个元素 (0 值初始化) 添加到 vec 的末尾;接下来调用 vec.resize(100) 则会将 vec 末尾的 90 个元素删除。
接受单个参数的 resize 版本对元素类型有什么限制(如果有的话)?
解答
特别地,对类类型的元素而言,调用 resize 时应提供扩增数及各新增元素的初始值;若未提供初始值,则要求该类型必须提供有一个默认构造函数。
第 316 页中删除偶数值元素并复制奇数值元素的程序不能用于 list 或 forward_list。为什么?修改程序,使之也能用于这些类型。
解答
对复合赋值运算而言,
iter += 1;
复合赋值语句所适用的容器为 string、vector、deque、array,所以要改为:
++iter; ++iter;
以达到相同的效果。
特别地,对 forward_list (基于单链表结构) 而言,还需要增加一个首前 (off-the-beginning) 迭代器 prev 并同时维护一对前驱/后继节点位置的迭代器:
- auto prev = flst.before_begin(); // 哨兵节点
- auto curr = flst.begin(); // 首节点
- //...
- curr = flst.insert_after(prev, *curr);
- ++curr; ++curr;
- ++prev; ++prev;
在第 316 页的程序中,向下面语句这样调用 insert 是否合法?如果不合法,为什么?
iter = vi.insert(iter, *iter++);
解答
在本节最后一个例子中,如果不将 insert 的结果赋予 begin,将会发生什么?编写程序,去掉此赋值语句,验证你的答案。
解答
源程序:
- #include <iostream>
- #include <vector>
- using namespace std;
-
- int main()
- {
- vector<int> data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
- for(auto iter = data.begin(); iter != data.end(); ++iter) {
- if(*iter % 2) {
- iter = data.insert(iter, *iter); // 复制奇数元素
- ++iter;
- }
- else {
- iter = data.erase(iter); // 删除偶数元素
- }
- }
- for (auto i : data)
- cout << i << " ";
- cout << endl;
-
- system("pause");
- return 0;
- }
输出:
1 3 5 7 9
假定 vi 是一个保存 int 的容器,其中有偶数值也有奇数值,分析下面循环的行为,然后编写程序验证你的分析是否正确。
iter = vi.begin(); while (iter != vi.end()) if (*iter % 2) iter = vi.insert(iter, *iter); ++iter;
解答
- #include <iostream>
- #include <vector>
- using namespace std;
-
- int main()
- {
- vector<int> vi = {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);
-
- for(auto begin = vi.cbegin(); begin != vi.cend(); ++begin)
- cout << *begin << " ";
- cout << endl;
- }
- ++iter;
-
- system("pause");
- return 0;
- }
// 无限循环输出 ...
- #include <iostream>
- #include <vector>
- #include <string>
- using namespace std;
-
- int main()
- {
- vector<int> vi = {1, 2, 3, 4, 5, 6, 7, 8, 9};
- auto iter = vi.begin();
- string tmp;
- while(iter != vi.end()) {
- if(*iter % 2) {
- iter = vi.insert(iter, *iter);
- ++iter;
- }
- ++iter;
- }
- for(auto begin = vi.begin(); begin != vi.end(); ++begin)
- cout << *begin << " ";
- cout << endl;
- cin >> tmp;
-
- system("pause");
- return 0;
- }
- 1 1 2 3 4 5 6 7 8 9
- 1 1 2 3 4 5 6 7 8 9
- 1 1 2 3 3 4 5 6 7 8 9
- 1 1 2 3 3 4 5 6 7 8 9
- 1 1 2 3 3 4 5 5 6 7 8 9
- 1 1 2 3 3 4 5 5 6 7 8 9
- 1 1 2 3 3 4 5 5 6 7 7 8 9
- 1 1 2 3 3 4 5 5 6 7 7 8 9
- 1 1 2 3 3 4 5 5 6 7 7 8 9 9
解释一个 vector 的 capacity 和 size 有何区别。
解答
一个容器的 capacity 可能小于它的 size 吗?
解答
由练习 9.35 可知不可能。
为什么 list 或 array 没有 capacity 成员函数?
解答
编写程序,探究在你的标准实现中,vector 是如何增长的。
解答
源程序:
- #include <iostream>
- #include <vector>
- using namespace std;
-
- int main()
- {
- vector<int> ivec;
- for(int i = 0; i < 100; ++i) {
- cout << "capacity: " << ivec.capacity() << " size: " << ivec.size() << endl;
- ivec.push_back(i);
- }
-
- system("pause");
- return 0;
- }
输出:
- capacity: 0 size: 0
- capacity: 1 size: 1
- capacity: 2 size: 2
- capacity: 4 size: 3
- capacity: 4 size: 4
- capacity: 8 size: 5
- capacity: 8 size: 6
- capacity: 8 size: 7
- capacity: 8 size: 8
- capacity: 16 size: 9
- capacity: 16 size: 10
- capacity: 16 size: 11
- capacity: 16 size: 12
- capacity: 16 size: 13
- capacity: 16 size: 14
- capacity: 16 size: 15
- capacity: 16 size: 16
- capacity: 32 size: 17
- capacity: 32 size: 18
- capacity: 32 size: 19
- capacity: 32 size: 20
- capacity: 32 size: 21
- capacity: 32 size: 22
- capacity: 32 size: 23
- capacity: 32 size: 24
- capacity: 32 size: 25
- capacity: 32 size: 26
- capacity: 32 size: 27
- capacity: 32 size: 28
- capacity: 32 size: 29
- capacity: 32 size: 30
- capacity: 32 size: 31
- capacity: 32 size: 32
- capacity: 64 size: 33
- capacity: 64 size: 34
- capacity: 64 size: 35
- capacity: 64 size: 36
- capacity: 64 size: 37
- capacity: 64 size: 38
- capacity: 64 size: 39
- capacity: 64 size: 40
- capacity: 64 size: 41
- capacity: 64 size: 42
- capacity: 64 size: 43
- capacity: 64 size: 44
- capacity: 64 size: 45
- capacity: 64 size: 46
- capacity: 64 size: 47
- capacity: 64 size: 48
- capacity: 64 size: 49
- capacity: 64 size: 50
- capacity: 64 size: 51
- capacity: 64 size: 52
- capacity: 64 size: 53
- capacity: 64 size: 54
- capacity: 64 size: 55
- capacity: 64 size: 56
- capacity: 64 size: 57
- capacity: 64 size: 58
- capacity: 64 size: 59
- capacity: 64 size: 60
- capacity: 64 size: 61
- capacity: 64 size: 62
- capacity: 64 size: 63
- capacity: 64 size: 64
- capacity: 128 size: 65
- capacity: 128 size: 66
- capacity: 128 size: 67
- capacity: 128 size: 68
- capacity: 128 size: 69
- capacity: 128 size: 70
- capacity: 128 size: 71
- capacity: 128 size: 72
- capacity: 128 size: 73
- capacity: 128 size: 74
- capacity: 128 size: 75
- capacity: 128 size: 76
- capacity: 128 size: 77
- capacity: 128 size: 78
- capacity: 128 size: 79
- capacity: 128 size: 80
- capacity: 128 size: 81
- capacity: 128 size: 82
- capacity: 128 size: 83
- capacity: 128 size: 84
- capacity: 128 size: 85
- capacity: 128 size: 86
- capacity: 128 size: 87
- capacity: 128 size: 88
- capacity: 128 size: 89
- capacity: 128 size: 90
- capacity: 128 size: 91
- capacity: 128 size: 92
- capacity: 128 size: 93
- capacity: 128 size: 94
- capacity: 128 size: 95
- capacity: 128 size: 96
- capacity: 128 size: 97
- capacity: 128 size: 98
- capacity: 128 size: 99
可见编译器是成倍增长 vector 容量的。
解释下面程序片段做了什么:
vector<string> svec; svec.reserve(1024); string word; while (cin >> word) svec.push_back(word); svec.resize(svec.size() + svec.size() / 2);
解答
首先,定义一个 vector 并为其分配 1024 个元素的空间。然后,通过一个循环从标准输入中读取字符串并末尾追加到 vector 中。循环结束后,改变 vector 的容器大小 (元素数量) 为原来的 1.5 倍,并使用元素的默认初始化值填充新增元素 (多出的 50%)。若容器大小超过 1024,vector 也会重新分配空间以容纳新增元素。
如果上一题的程序读入了 256 个词,在 resize 之后容器的 capacity 可能是多少?如果读入了 512 个、1000 个、或1048 个呢?
解答
编写程序,从一个 vector<char> 初始化一个 string。
解答
源程序:
- #include <iostream>
- #include <vector>
- #include <string>
- using namespace std;
-
- int main()
- {
- vector<char> cvec = {'h', 'e', 'l', 'l', 'o'};
- string str(cvec.data(), cvec.size()); // 传入首地址及大小
- // 给定迭代器范围亦可 string str(cvec.begin(), cvec.end());
- cout << str << endl;
-
- system("pause");
- return 0;
- }
输出:
hello
假定你希望每次读取一个字符存入一个 string 中,而且知道最少需要读取 100 个字符,应该如何提高程序的性能?
解答
由于已知至少读取 100 个字符,故可用 reverse 函数预先为 string分配 100 个字符的内存空间,然后再逐个读取字符,并用 push_back 末尾追加到 string 中。
源程序:
- #include <iostream>
- #include <vector>
- #include <string>
- using namespace std;
-
- void input_string(string s)
- {
- s.reserve(100); // 预分配 100 个元素的空间
- char c;
- while(cin >> c)
- s.push_back(c);
- }
-
- int main()
- {
- string str;
- input_string(str);
- cout << str << endl;
-
- system("pause");
- return 0;
- }
编写一个函数,接受三个 string 参数 s、oldVal 和 newVal。使用迭代器及 insert 和 erase 函数将 s 中所有 oldVal 替换为 newVal。测试你的程序,用它替换通用的简写形式,如,将 "tho" 替换为 "though",将 "thru" 替换为 "through" 。
解答
源程序:
- #include <iostream>
- #include <vector>
- #include <string>
- using namespace std;
-
- void replace_string(string &s, const string &oldVal, const string &newVal) // 注意形参类型
- {
- if(oldVal.empty() || (s.size() < oldVal.size())) // 异常情况
- return;
-
- auto iter = s.begin(); // s 迭代器
- while(iter <= (s.end()-oldVal.size())) {
- auto iter1 = iter; // 拷贝 s 迭代器
- auto iter2 = oldVal.begin(); // 新建 oldVal 迭代器
- // s 中 iter 开始的子串必须每个字符都与 oldVal 相同
- while(iter2 != oldVal.end() && *iter1 == *iter2) {
- ++iter1;
- ++iter2;
- }
- if(iter2 == oldVal.end()) { // oldVal 耗尽 —— 字符串相等
- iter = s.erase(iter, iter+oldVal.size()); // 删除 s 中与 oldVal 相等部分 (迭代器范围)
- if(newVal.size()) {
- auto iter3 = newVal.end(); // 新建newVal 迭代器
- do {
- --iter3;
- iter = s.insert(iter, *iter3);
- } while(iter3 > newVal.begin());
- }
- iter += newVal.size(); // 迭代器移动到新插入内容之后
- }
- else
- ++iter; // s 迭代器后移一位
- }
- }
-
- int main()
- {
- string s = "the thru tho!";
- replace_string(s, "thru", "through");
- cout << s << endl;
-
- replace_string(s, "tho", "though");
- cout << s << endl;
-
- replace_string(s, "through", "");
- cout << s << endl;
-
- system("pause");
- return 0;
- }
输出:
- the through tho!
- the through though!
- the though!
重写上一题的函数,这次使用一个下标和 replace。
解答
源程序:
- #include <iostream>
- #include <vector>
- #include <string>
- using namespace std;
-
- void replace_string(string &s, const string &oldVal, const string &newVal) // 注意形参类型
- {
- if(oldVal.empty() || (s.size() < oldVal.size())) // 异常情况
- return;
-
- auto index = 0;
- auto range = s.size() - oldVal.size();
- while(index <= range) {
- auto index1 = index; // 拷贝当前 s 索引
- auto index2 = 0; // 新建 oldVal 索引
- // 逐个检查相等与否
- while(index2 < oldVal.size() && s[index1] == oldVal[index2]) {
- ++index1;
- ++index2;
- }
- // 相等则替换并后移新增位数, 否则正常后移一位
- if(index2 == oldVal.size()) {
- s.replace(index, oldVal.size(), newVal);
- index += newVal.size();
- }
- else
- ++index;
- }
- }
-
- int main()
- {
- string s = "the thru tho!";
- replace_string(s, "thru", "through");
- cout << s << endl;
-
- replace_string(s, "tho", "though");
- cout << s << endl;
-
- replace_string(s, "through", "");
- cout << s << endl;
-
- system("pause");
- return 0;
- }
输出:
- the through tho!
- the through though!
- the though!
源程序:
- #include <iostream>
- #include <vector>
- #include <string>
- using namespace std;
-
- void replace_string(string &s, const string &oldVal, const string &newVal) // 注意形参类型
- {
- int index = 0;
- while((index = s.find(oldVal, index)) != string::npos) { // 在 s 中使用 find() 查找 oldVal
- s.replace(index, oldVal.size(), newVal); // 将找到的子串替换为 newVal
- index += newVal.size(); // 下标调整到新插入的内容后
- }
- }
-
- int main()
- {
- string s = "the thru tho!";
- replace_string(s, "thru", "through");
- cout << s << endl;
-
- replace_string(s, "tho", "though");
- cout << s << endl;
-
- replace_string(s, "through", "");
- cout << s << endl;
-
- system("pause");
- return 0;
- }
输出:
- the through tho!
- the through though!
- the though!
编写一个函数,接受一个表示名字的 string 参数和两个分别表示前缀(如 "Mr." 或 "Mrs." )和后缀(如 "Jr." 或 "III" )的字符串。使用迭代器及 insert 和 append 函数将前缀和后缀添加到给定的名字中,将生成的新 string 返回。
解答
源程序:
- #include <iostream>
- #include <string>
- using namespace std;
-
- string fix_prefix_and_suffix(string &name, const string &prefix, const string &suffix) // 注意形参类型
- {
- // name = prefix + name + suffix;
- name.insert(name.begin(), 1, ' '); // 注意区别
- name.insert(name.begin(), prefix.begin(), prefix.end()); // 不能只写个 prefix
- name.append(" "); // 注意区别
- name.append(suffix.begin(), suffix.end()); // 不能只写个 suffix
- return name;
- }
-
- int main()
- {
- string s = "Wang";
- cout << fix_prefix_and_suffix(s, "Dear", "x") << endl;
-
- system("pause");
- return 0;
- }
输出:
Dear Wang x
重写上一题的函数,这次使用位置和长度来管理string,并只使用insert。
解答
源程序:
- #include <iostream>
- #include <string>
- using namespace std;
-
- string fix_prefix_and_suffix(string &name, const string &prefix, const string &suffix) // 注意形参类型
- {
- name.insert(0, " ");
- name.insert(0, prefix);
- name.insert(name.size(), " ");
- name.insert(name.size(), suffix);
- return name;
- }
-
- int main()
- {
- string s = "Wang";
- cout << fix_prefix_and_suffix(s, "Dear", "x") << endl;
-
- system("pause");
- return 0;
- }
输出:
Dear Wang x
编写程序,首先查找 string "ab2c3d7R4E6" 中每个数字字符,然后查找其中每个字母字符。编写两个版本的程序,第一个要使用 find_first_of,第二个要使用 find_first_not_of。
解答
稍微修改题求并混合书写,源程序:
- #include <iostream>
- #include <string>
- using namespace std;
-
- void find_char(string &s, const string& c)
- {
- int pos1 = 0;
- while((pos1 = s.find_first_of(c, pos1)) != string::npos) {
- cout << s[pos1] << " ";
- ++pos1;
- }
- cout << endl;
-
- for(int pos2 = 0; (pos2 = s.find_first_not_of(c, pos2)) != string::npos; ++pos2) {
- cout << s[pos2] << " ";
- }
- cout << endl;
- }
-
- int main()
- {
- string str = "ab2c3d7R4E6";
- string number = "0123456789";
- string alpha = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
-
- find_char(str, number);
- find_char(str, alpha);
-
- system("pause");
- return 0;
- }
输出:
- 2 3 7 4 6
- a b c d R E
- a b c d R E
- 2 3 7 4 6
假定 name 和 numbers 的定义如 325 页所示,numbers.find(name) 返回什么?
解答
如果一个字母延伸到中线之上,如 d 或 f,则称其有上出头部分(ascender)。如果一个字母延伸到中线之下,如 p 或 g,则称其有下出头部分(descender)。编写程序,读入一个单词文件,输出最长的既不包含上出头部分,也不包含下出头部分的单词。
解答
源程序:
- #include <iostream>
- #include <fstream>
- #include <string>
- using namespace std;
-
- void find_longest_word(ifstream &in)
- {
- string s, longest_word;
- string alpha = "bdfghjklpqty";
- int max_length = 0;
-
- while(in >> s) {
- if(s.find_first_of(alpha) != string::npos)
- continue;
- cout << s << " ";
- if(max_length < s.size()) {
- max_length = s.size();
- longest_word = s;
- }
- }
- cout << "the longest specific string is " << longest_word << endl;
- }
-
- int main(int argc, char* argv[])
- {
- ifstream in(argv[1]); // 打开文件
- if(!in) {
- cerr << "can not open the input file" << endl;
- return -1;
- }
- find_longest_word(in);
-
- system("pause");
- return 0;
- }
编写程序处理一个 vector<string>,其元素都表示整型值。计算 vector 中所有元素之和。修改程序,使之计算表示浮点值的 string 之和。
解答
- #include <iostream>
- #include <vector>
- #include <string>
- using namespace std;
-
- int main()
- {
- vector<string> svec = {"123", "+456", "-789"};
- int sum = 0;
- for(auto iter = svec.cbegin(); iter != svec.cend(); ++iter)
- sum += stoi(*iter);
- cout << "sum: " << sum << endl;
-
- system("pause");
- return 0;
- }
sum: -210
- #include <iostream>
- #include <vector>
- #include <string>
- using namespace std;
-
- int main()
- {
- vector<string> svec = {"12.3", "-4.56", "+7.8e-2"};
- float sum = 0;
- for(auto iter = svec.cbegin(); iter != svec.cend(); ++iter)
- sum += stof(*iter);
- cout << "sum: " << sum << endl;
-
- system("pause");
- return 0;
- }
sum: 7.818
设计一个类,它有三个 unsigned 成员,分别表示年、月和日。为其编写构造函数,接受一个表示日期的 string 参数。你的构造函数应该能处理不同的数据格式,如 January 1,1900、1/1/1990、Jan 1 1900 等。
解答
使用 stack 处理括号化的表达式。当你看到一个左括号,将其记录下来。当你在一个左括号之后看到一个右括号,从 stack 中 pop 对象,直至遇到左括号,将左括号也一起弹出栈。然后将一个值(括号内的运算结果)push到栈中,表示一个括号化的(子)表达式已经处理完毕,被其运算结果所替代。
解答
本题可延伸为 逆波兰求值 及 中缀转后缀表达式。
源程序:
- #include <iostream>
- #include <string>
- #include <stack>
- using namespace std;
-
- int main()
- {
- string expression = "hello world (dear)";
- bool bracket_seen = false;
- stack<char> stack;
- for (const auto &s : expression){
- if(s == '(') {
- bracket_seen = true;
- continue;
- }
- else if(s == ')')
- bracket_seen = false;
-
- if(bracket_seen)
- stack.push(s);
- }
-
- string reverse_str;
- while (!stack.empty()){
- reverse_str += stack.top();
- stack.pop();
- }
-
- expression.replace(expression.find("(") + 1, reverse_str.size(), reverse_str);
- cout << expression << endl;
-
- system("pause");
- return 0;
- }
输出:
hello world (raed)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。