第九章 顺序容器练习题
9.1
(a) list
(b) deque
(c) vector
9.2
list<deque<int>> a;
9.3
指向同一个容器,并且end不在begin之前。
9.4
bool find(vector<int>::iterator b, vector<int>::iterator e, int x) {
while (b != e) {
if (*b == x) return true;
b ++;
}
return false;
}
9.5
using vit = vector<int>::iterator;
vit find(vit b, vit e, int x) {
while (b != e) {
if (*b == x) return b;
b ++;
}
cout << "vector中不存在" << x << endl;
exit(0);
}
9.6
list迭代器不支持 < 运算符
9.7
vector<int>::size_type
9.8
读:list<string>::const_iterator
写:list<string>::iterator
9.9
begin返回的iterator要看容器类型,如果容器是const则返回const_iterator;如果容器非const,就返回iterator。而cbegin则显式的指定返回类型为const_iterator,与容器无关。
9.10
it1: vector<int> iterator;
it2, it3, it4: vector<int> const_iterator;
由于 it1 与 it2 的类型不一致,所以书中的 auto it1 = v1.begin(), it2 = v2.begin() 有误。
9.11
(1) vector<int> a; // 空的vector
(2) vector<int> a(10); // 大小为10,值被默认初始化为0
(3) vector<int> a(10, 1); // 大小为10,值被初始化为1
(4) vector<int> a = {1, 2, 3, 4, 5} // 列表初始化
(5) vector<int> b;
vector<int> a(b);
vector<int> a = b; // 拷贝初始化,与上面等价
(6) vector<int> a(b.begin(), b.end()); // 迭代器范围初始化
9.12
接受容器要求容器的类型和其元素类型一致才行,接受迭代器范围则不要求容器类型一致,其元素类型也可以不一致,只要能够转换即可。
9.13
使用迭代器范围初始化
9.14
使用assign
9.15
可直接使用==运算符
9.16
bool judge(vector<int> a, list<int> b) {
if (a.size() != b.size()) return false;
vector<int>::const_iterator vit1 = a.cbegin(), vit2 = a.cend();
list<int>::const_iterator lit = b.cbegin();
while (vit1 != vit2) {
if (*vit1 != *lit) return false;
vit1 ++;
lit ++;
}
return true;
}
9.17
(1) c1 和 c2 必须是同一类型的容器,且必须保存相同类型的元素;
(2) 容器中保存的元素必须定义了 < 运算符。
9.18
void code_9_18() {
string str;
deque<string> ds;
while (cin >> str) ds.push_back(str);
using ds_cit = deque<string>::const_iterator;
for (ds_cit it = ds.cbegin(); it != ds.cend(); it ++) cout << *it << endl;
}
9.19
void code_9_19() {
string str;
list<string> ls;
while (cin >> str) ls.push_back(str);
using ls_cit = list<string>::const_iterator;
for (ls_cit it = ls.cbegin(); it != ls.cend(); it ++) cout << *it << endl;
}
9.20
void code_9_20() {
list<int> ilst = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
deque<int> odd, even;
for (const auto & it : ilst) {
if (it & 1) odd.push_back(it);
else even.push_back(it);
}
cout << "odd: ";
for (const auto & it : odd) cout << it << " ";
cout << endl << "even: ";
for (const auto & it : even) cout << it << " ";
}
9.21
由于vector是顺序容器,所以在执行insert操作时,从iter开始之后的所有的元素都要后移一位。
9.22
(1) 迭代器iter没有递增;
(2) vector在insert操作后,原迭代器会失效(P305)
修改如下:
void code_9_22() {
vector<int> iv = {2, 2, 1, 3, 5};
int some_val = 2;
vector<int>::iterator iter = iv.begin(), mid = iv.begin() + iv.size() / 2;
int tmp = iv.size() / 2;
while (iter != mid) {
if (*iter == some_val) {
iter = iv.insert(iter, 2 * some_val) + 1;
mid = iv.begin() + (++tmp);
}
iter ++;
}
for (const auto &it : iv) cout << it << " ";
}
9.23
都指向一个元素,也是 c 中的唯一元素
9.24
vector<int> iv;
//terminate called after throwing an instance of 'std::out_of_range'
int a = iv.at(0);
// 以下均运行时错误
int b = iv[0];
int c = iv.front();
int d = *iv.begin();
9.25
(1) elem1 = elem2: 不发生删除
(2) elem2 = 尾后迭代器:删除从elem1开始之后的所有元素(包括elem1)
(3) elem1 = elem2 = 尾后迭代器:不发生删除
9.26
void code_9_26() {
int ia[] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 55, 89 };
vector<int> iv;
list<int> il;
iv.assign(begin(ia), end(ia));
il.assign(begin(ia), end(ia));
vector<int>::iterator it1 = iv.begin();
list<int>::iterator it2 = il.begin();
while (it1 != iv.end() && it2 != il.end()) {
if (*it2 & 1) {
it2 = il.erase(it2);
it1 ++;
} else {
it1 = iv.erase(it1);
it2 ++;
}
}
for (const auto &it : iv) cout << it << " "; cout << endl;
for (const auto &it : il) cout << it << " "; cout << endl;
}
9.27
void code_9_27() {
forward_list<int> flst = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 55, 89 };
auto p = flst.before_begin(), c = flst.begin();
while (c != flst.end()) {
if (*c & 1) {
c = flst.erase_after(p);
} else {
p = c;
c ++;
}
}
for (const auto &it : flst) cout << it << " ";
}
9.28
void code_9_28(forward_list<string> &flst, string s1, string s2) {
forward_list<string>::const_iterator it1 = flst.cbegin(), it2 = flst.cbefore_begin();
while (it1 != flst.cend()) {
if (*it1 == s1) { // 找到第一个string
flst.insert_after(it1, s2);
return;
}
it1 ++;
it2 ++;
}
flst.insert_after(it2, s2);
}
9.29
vec.resize(100): 将vec扩展到100个元素,后面新加的75个元素都为0
vec.resize(10): 删除vec后面的90个元素,保留前10个
9.30
接受单个参数,如果容器保存的是类类型元素,则该类必须提供一个默认构造函数
9.31
对于list和forward_list的迭代器不支持+=运算符,并且forward_list没有insert和erase方法
对于list只需要将 iter+=2; 修改为 iter++; iter++; 即可
对于 forward_list:
forward_list<int> fli = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
auto it1 = fli.before_begin(), it2 = fli.begin();
while (it2 != fli.end()) {
if (*it2 % 2) {
it1 = fli.insert_after(it1, *it2);
it2 ++;
it1 ++;
} else {
it2 = fli.erase_after(it1);
}
}
9.32
不合法。
函数调用时,参数的进栈顺序是从右往左,所以会先执行 *iter++;(第一个参数iter后进栈,并发生了改变)
由于 * 和 ++ 优先级一样,但 *iter++是从右往左运算,所以先计算 ++,再计算*,但是由于iter++是先返回iter,再执行++运算,所以*iter等价于 *iter; iter++;这样导致实际的插入位置是原iter的后一个位置,所以返回后iter指向当前插入的元素(但是在原处理奇数元素的后面),而后再执行 iter+=2 就会跳过一个元素没有处理,并且这可能会导致 iter 迭代器失效。
将 iter += 2; 改为 iter ++; 即可。
9.33
begin 会失效
9.34
程序的目的是想将奇数在它位置上复制一份,如 { 1,2,3,4 } 执行应得到:{ 1,1,2,3,3,4 }
但是由于在插入元素的 if 条件里迭代器没有自增到当前处理的元素,导致了死循环。
9.35
size: 容器中已经保存的元素的个数
capacity: 容器在不分配新的内存空间的前提下最多可以保存多少个元素
9.36
不可能
9.37
对于 array 来说,在创建的时候就已经固定了大小,不可以改变。
对于 list 来说,它每一个元素在内存中的位置不一定是连续的,所以不需要 capacity。
9.38
void code_9_38() {
vector<int> vi;
int x;
while (cin >> x) {
vi.push_back(x);
cout << "size = " << vi.size() << " capactity = " << vi.capacity() << endl;
}
}
9.39
创建一个保存 string 的 vector,并为容器分配可以保存1024个元素的内存空间。
再从输入中读取单词保存到容器中,最后扩展容器的 size,后面有三分之一的元素为空字符串。resize 并不会减少容器的容量,但可能会增加。如果 resize 操作后,size > 1024(针对本题分配好的空间),那么 capacity 会增加。
9.40
void code_9_40(int n) {
vector<string> svec;
svec.reserve(1024);
for (int i = 1; i <= n; i ++) svec.push_back("hi");
svec.resize(svec.size() + svec.size() / 2);
cout << "读取" << n << "个单词:size = " << svec.size() << " capacity = " << svec.capacity() << endl;
}
调用函数如下:
code_9_40(256);
code_9_40(512);
code_9_40(1000);
code_9_40(1048);
输出结果如下:
读取256个单词:size = 384 capacity = 1024
读取512个单词:size = 768 capacity = 1024
读取1000个单词:size = 1500 capacity = 2000
读取1048个单词:size = 1572 capacity = 2048
9.41
void code_9_41() {
vector<char> vc = { 'h', 'e', 'l', 'l', 'o' };
string s(vc.cbegin(), vc.cend());
cout << s << endl;
}
9.42
可以使用 reserve 预分配出足够的容量
9.43
void code_9_43(string &s, string oldVal, string newVal) {
using sit = string::iterator;
for (sit it1 = s.begin(); it1 + oldVal.size() - 1 < s.end(); it1 ++) {
sit it2 = it1, it3 = oldVal.begin();
while (*it2 == *it3) {
it2 ++;
it3 ++;
if (it3 == oldVal.end()) {
it1 = s.erase(it1, it2);
it1 = s.insert(it1, newVal.cbegin(), newVal.cend());
it1 += newVal.size() - 1;
break;
}
}
}
}
9.44
void code_9_44(string &s, string oldVal, string newVal) {
for (int i = 0; i + oldVal.size() - 1 < s.size(); i ++) {
if (s.substr(i, oldVal.size()) == oldVal) {
s.replace(i, oldVal.size(), newVal);
i += newVal.size() - 1;
}
}
}
9.45
string code_9_45(const string &name, const string &pre, const string &suf) {
string ret = name;
ret.insert(ret.begin(), pre.cbegin(), pre.cend());
ret.append(suf);
return ret;
}
9.46
string code_9_46(const string &name, const string &pre, const string &suf) {
string ret = name;
ret.insert(0, pre, 0, pre.size());
ret.insert(ret.size(), suf, 0, suf.size());
return ret;
}
9.47
void code_9_47() {
string::size_type pos = 0;
string s("ab2c3d7R4E6"), numbers("0123456789");
while ((pos = s.find_first_of(numbers, pos)) != string::npos) {
cout << s[pos] << endl;
pos ++;
}
puts("========================");
pos = 0;
while ((pos = s.find_first_not_of(numbers, pos)) != string::npos) {
cout << s[pos] << endl;
pos ++;
}
}
9.48
string::npos
9.49
void code_9_49() {
string valid("acemnorsuvwxz");
ifstream in("words.txt");
string s, mx_s;
while (in >> s) {
if (s.find_first_not_of(valid) == string::npos && s.size() > mx_s.size()) mx_s = s;
}
cout << mx_s << endl;
}
9.50
void code_9_50() {
vector<string> vs_i(10, "100"), vs_d(10, "10.5");
int i_sum = 0; double d_sum = 0;
for (const auto &it : vs_i) i_sum += stoi(it);
for (const auto &it : vs_d) d_sum += stod(it);
cout << i_sum << " " << d_sum << endl;
}
9.51
void code_9_51() {
class Date {
public:
vector<string> mons = { "", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec" };
unsigned year, month, day;
Date(string str) {
// 根据 '空格',','和'/'划分为三个字符串
string _year, _month, _day;
string::size_type pos1 = str.find_first_of(", /");
string::size_type pos2 = str.find_last_of(", /");
_month = str.substr(0, pos1);
_day = str.substr(pos1 + 1, pos2 - pos1 - 1);
_year = str.substr(pos2 + 1);
// 如果月份用英文表达
if (_month.find_first_of("0123456789") == string::npos) {
for (int i = 1; i <= 12; i ++) {
if (_month.find(mons[i]) != string::npos) {
_month = to_string(i);
break;
}
}
}
year = stoi(_year);
month = stoi(_month);
day = stoi(_day);
};
void print() {
cout << year << "年" << month << "月" << day << "日" << endl;
}
};
string tmp;
while (getline(cin, tmp)) {
Date date(tmp);
date.print();
}
}
9.52
void code_9_52(string str) {
// str = (((3*5)+10)*(((20-4)*5)/5))
stack<int> intSk;
stack<char> chSk;
for (int i = 0; i < str.size(); i ++) {
if (str[i] == ')') {
int b = intSk.top(); intSk.pop();
int a = intSk.top(); intSk.pop();
char c = chSk.top(); chSk.pop(); chSk.pop(); // 先弹出操作符,再弹出左括号
switch (c) {
case '+':
intSk.push(a + b);
break;
case '-':
intSk.push(a - b);
break;
case '*':
intSk.push(a * b);
break;
case '/':
intSk.push(a / b);
break;
}
} else if (str[i] >= '0' && str[i] <= '9') {
string::size_type pos = str.find_first_not_of("0123456789", i + 1);
intSk.push(stoi(str.substr(i, pos - i)));
i = pos - 1;
} else chSk.push(str[i]);
}
cout << str << " = " << intSk.top() << endl; // 最后的结果
}