练习 9.1:
(a) list较好,涉及到可能在中间插入的操作
(b) deque较好,因为涉及到在头部删除,末尾插入的操作,都是在两端进行。
(c) vector较好,没有更好的选择。
练习 9.2:
list<deque<int>> l
练习 9.3:
迭代器begin和end必须指向相同的容器。end可以与begin指向相同的位置,但不能指向begin之前的位置。
练习 9.4:
#include<iostream>
#include<vector>
using namespace std;
using iter = vector<int>::const_iterator;
bool find_int(iter beg, iter end, int i)
{
while (beg != end)
{
if (*beg == i)
return true;
++beg;
}
return false;
}
int main()
{
vector<int> vec{ 1,2,3,4,5,6,7,8,9 };
bool ret = find_int(vec.begin(), vec.end(), 6);
cout << boolalpha << ret << endl;
return 0;
}
练习 9.5:
#include<iostream>
#include<vector>
using namespace std;
using iter = vector<int>::const_iterator;
iter find_int(iter beg, iter end, int i)
{
while (beg != end)
{
if (*beg == i)
return beg;
++beg;
}
return end; // 未找到元素返回末尾迭代器
}
int main()
{
vector<int> vec{ 1,2,3,4,5,6,7,8,9 };
auto ret = find_int(vec.begin(), vec.end(), 6);
cout << ret - vec.begin() << endl;
return 0;
}
练习 9.6:
迭代器支持的算术运算不能用于list容器,因为list容器不是按照顺序存储的,他是个双向链表,改成while (iter1 != iter2)。
练习 9.7:
vector<int>::iterator
练习 9.8:
list<string>::value_type
list<string>::const_reference
练习 9.9:
begin函数返回的是iterator,而cbegin函数返回的是const_iterator。
练习 9.10:
v1是一个int型元素的vecor容器; v2是一个int型常量元素的vector容器;
it1、it2是vector<int>::iterator; it3、it4是const_iterator
练习 9.11:
#include<iostream>
#include<vector>
using namespace std;
ostream& print(ostream& os, vector<int> vec)
{
for (auto iter = vec.cbegin(); iter != vec.cend(); ++iter)
os << *iter << " ";
return os;
}
int main()
{
vector<int> vec1;
print(cout, vec1) << endl;
for (int i = 0; i != 10; ++i)
vec1.push_back(i);
vector<int> vec2(vec1);
print(cout, vec2) << endl;
vector<int> vec3 = vec1;
print(cout, vec2) << endl;
vector<int> vec4{ 6,6,6 };
print(cout, vec4) << endl;
vector<int> vec5 = { 6,6,6, };
print(cout, vec5) << endl;
vector<int> vec6(vec1.begin(), vec1.end());
print(cout, vec6) << endl;
/*
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
6 6 6
6 6 6
0 1 2 3 4 5 6 7 8 9
*/
return 0;
}
练习 9.12:
接受两个迭代器的拷贝构造函数可以将一个容器内的子序列进行拷贝,而接收一个容器创建其拷贝的构造函数拷贝的是整个容器所有的元素。而且为了创建一个容器为另外一个容器的拷贝,两个容器的类型及其元素类型必须匹配,当传递迭代器参数来拷贝一个范围时,就不要求容器类型是相同的了,新容器和原容器中的元素类型也可以不同,只要能将拷贝的元素转换为要初始化的容器的元素类型即可。
练习 9.13:
#include<iostream>
#include<string>
#include<vector>
#include<list>
using namespace std;
template<typename T>
ostream& print(ostream& os, T container)
{
for (auto elem : container)
os << elem << " ";
return os;
}
int main()
{
list<int> lst{ 0,1,2,3,4,5,6 };
vector<int> ivec{ 7,7,7,7,7,7,7 };
vector<double> dvec(lst.begin(), lst.end());
print(cout, dvec) << endl;
vector<double> dvec2(ivec.begin(), ivec.end());
print(cout, dvec2) << endl;
return 0;
}
练习 9.14:
#include<iostream>
#include<string>
#include<vector>
#include<list>
using namespace std;
template<typename T>
ostream& print(ostream& os, T container)
{
for (auto elem : container)
os << elem << " ";
return os;
}
int main()
{
list<const char*> lst{ "Cpp", "Java", "Python"};
vector<string> vec(lst.begin(), lst.end()); // 初始化
vector<string> vec2;
vec2.assign(lst.begin(), lst.end()); // 赋值
print(cout, lst) << endl;
print(cout, vec) << endl;
print(cout, vec2) << endl;
return 0;
}
练习 9.15:
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> vec1{ 0,1,2,3,4,5 };
vector<int> vec2{ 0,1,2,3,4,5 };
vector<int> vec3{ 0,1,2,3,4,5,6 };
cout << boolalpha << (vec1 == vec2) << endl;
cout << boolalpha << (vec1 == vec3) << endl;
return 0;
}
练习 9.16:
#include<iostream>
#include<vector>
#include<list>
using namespace std;
int main()
{
list<int> lst{ 0,1,2,3,4,5 };
vector<int> vec1{ 0,1,2,3,4,5 };
vector<int> vec2{ 0,1,2,3,4,5,6 };
cout << boolalpha << (vector<int>(lst.begin(), lst.end()) == vec1) << endl;
cout << boolalpha << (vector<int>(lst.begin(), lst.end()) == vec2) << endl;
return 0;
}
练习 9.17:
首先,容器类型必须相同,元素类型也必须相同。其次,元素类型必须定义了<运算符。
练习 9.18:
#include<iostream>
using namespace std;
#include<deque>
int main()
{
deque<string> dq;
/*string word;
while (cin >> word)
{
dq.push_back(word);
}*/
for (string word; cin >> word; dq.push_back(word));
for (auto elem : dq)
cout << elem << " ";
cout << endl;
return 0;
}
练习 9.19:
#include<iostream>
using namespace std;
#include<list>
int main()
{
list<string> lst;
for (string word; cin >> word; lst.push_back(word));
for (auto elem : lst)
cout << elem << " ";
cout << endl;
return 0;
}
练习 9.20:
#include<iostream>
using namespace std;
#include<list>
#include<deque>
ostream& print(ostream& os, deque<int> deq)
{
for (auto elem : deq)
os << elem << " ";
return os;
}
int main()
{
list<int> lst{ 0,1,2,3,4,5,6,7,8,9 };
deque<int> odd, even;
for (auto elem : lst)
{
/*if (elem % 2)
odd.push_back(elem);
else
even.push_back(elem);*/
(elem % 2 ? odd : even).push_back(elem); // 使用条件运算符 可以简化代码
}
print(cout, odd) << endl;
print(cout, even) << endl;
return 0;
}
练习 9.21:
循环将新元素插入到vector的首元素之前的位置。
练习9.22:
循环中未对iter进行递增操作,将陷入无限循环。其次,即使加入了++iter语句,由于向iv插入元素后,迭代器iter和mid已经失效。
练习9.23:
#include<iostream>
using namespace std;
#include<vector>
void insertDoubleValue(vector<int>& iv, int some_val)
{
auto iter = iv.begin(), mid = iv.begin() + iv.size() / 2;
while (iter != mid)
{
if (*iter == some_val)
{
iter = iv.insert(iter, 2 * some_val);
++iter;
mid = iv.begin() + iv.size() / 2; // 向iv插入元素后,mid已经失效,重新设定mid
++mid;
}
++iter;
}
}
ostream& print(ostream& os, vector<int> iv)
{
for (auto i : iv)
cout << i << " ";
return os;
}
int main()
{
vector<int> iv = {1, 2, 2, 3, 4,5};
insertDoubleValue(iv, 2);
print(cout, iv) << endl;
return 0;
}
练习 9.23:
4个变量的值指向唯一的一个元素。
练习 9.24:
#include<iostream>
using namespace std;
#include<vector>
int main()
{
vector<int> iv;
cout << iv.at(0) << endl;
cout << iv[0] << endl;
cout << iv.front() << endl;
cout << *iv.begin() << endl;
return 0;
}
练习 9.25:
如果两个迭代器elem1和elem2相等,则容器保持不变。如果elem2为尾后迭代器,则会删除从elem1开始直至elem2之前的所有元素。如果elem1和elem2都是尾后迭代器时,容器保持不变。
练习 9.26:
#include<iostream>
using namespace std;
#include<vector>
#include<list>
template<typename T>
ostream& print(ostream& os, T container)
{
for (auto elem : container)
os << elem << " ";
return os;
}
int main()
{
int ia[] = { 0,1,1,2,3,5,8,12,21,55,89 };
vector<int> vec(begin(ia), end(ia));
list<int> lst(begin(ia), end(ia));
// 删除奇数元素
for (auto it = lst.begin(); it != lst.end();)
{
if (*it % 2)
it = lst.erase(it);
else
++it;
}
// 删除偶数元素
for (auto it = vec.begin(); it != vec.end();)
{
if (!(*it % 2))
it = vec.erase(it);
else
++it;
}
print(cout, lst) << endl;
print(cout, vec) << endl;
return 0;
}
练习 9.28:
#include<iostream>
using namespace std;
#include<forward_list>
int main()
{
forward_list<int> flst{ 0,1,2,3,4,5,6,7,8,9 };
for (auto prev = flst.before_begin(), curr = flst.begin(); curr != flst.end();)
{
if (*curr % 2)
curr = flst.erase_after(prev);
else
prev = curr++;
}
for (auto elem : flst)
cout << elem << " ";
cout << endl;
return 0;
}
练习 9.28:
#include<iostream>
using namespace std;
#include<forward_list>
void find_and_insert(forward_list<string>& flst,
const string& str_find, const string& str_add)
{
bool flag = false; // 创建flag判断是否找到第一个string
auto prev = flst.before_begin();
for (auto curr = flst.begin(); curr != flst.end(); prev = curr++)
{
if (*curr == str_find)
{
curr = flst.insert_after(curr, str_add);
flag = true; // 找到第一个string
}
}
if (!flag)
flst.insert_after(prev, str_add); // prev指向最后一个元素
}
int main()
{
forward_list<string> flst{ "Cpp", "Java", "Pytghon"};
find_and_insert(flst, "Java", "Golang");
for (auto elem : flst)
cout << elem << " ";
cout << endl;
return 0;
}
练习 9.29:
调用vec.resize(100)会向vec末尾添加75个元素,这些元素将进行值初始化。接下来调用vec.size(10)会将vec末尾90个元素删除。
练习 9.30:
如果容器保存的是类类型元素,则单参数resize版本要求该元素类型必须提供一个默认构造函数。
练习 9.31:
list和forward_list与其他容器的一个不同是,迭代器不支持加减运算,因为链表中元素并非在内存中连续存储,无法通过地址的加减在元素间远距离移动,可以多次调用++来实现与迭代器加法相同的效果。
#include<iostream>
using namespace std;
#include<list>
void find_and_insert(forward_list<string>& flst,
const string& str_find, const string& str_add)
{
bool flag = false; // 创建flag判断是否找到第一个string
auto prev = flst.before_begin();
for (auto curr = flst.begin(); curr != flst.end(); prev = curr++)
{
if (*curr == str_find)
{
curr = flst.insert_after(curr, str_add);
flag = true; // 找到第一个string
}
}
if (!flag)
flst.insert_after(prev, str_add); // prev指向最后一个元素
}
int main()
{
list<int> lst = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
auto iter = lst.begin();
while (iter != lst.end()) {
if (*iter % 2) {
iter = lst.insert(iter, *iter);
++iter;
++iter;
}
else
iter = lst.erase(iter);
}
for (auto i : lst)
cout << i << " ";
cout << endl;
return 0;
}
练习 9.32:
该语句是非法的,因为在参数的求值顺序是未指定的。因此,在输入函数insert之后,iter可以是它的原始值或原始值+ 1,甚至是任何其他值,这取决于编译器如何实现。
练习 9.33:
向vector中插入新元素后,原有迭代器都会失效。因此,不将insert()返回的迭代器赋予begin,会使begin失效。继续使用begin会导致程序崩溃。
练习 9.34:
陷入死循环。复制奇数元素。即使while循环加上括号,它仍然是无限循环。
#include<iostream>
using namespace std;
#include<vector>
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;
}
for (auto i : vi)
cout << i << " ";
return 0;
}
练习 9.35:
容器的size是指它已经保存的元素的数目;而capacity则是在不分配新的内存空间的前提下它最多可以保存多少元素。
练习 9.36:
不可能。
练习 9.37:
list是链表,当有新元素插入时,会从内存空间分配一个新节点保存它;当从链表中删除元素时,该节点占用的内存空间会被立刻释放。因此一个链表占用的内存空间总是与当前保存的元素所需的空间相等。而array是固定大小数组,内存一次性分配,大小不变,不会变化,因此它们均不需要capacity。
练习 9.38:
#include<iostream>
using namespace std;
#include<string>
#include<vector>
int main()
{
vector<string> vec;
string str;
while (cin >> str)
{
vec.push_back(str);
cout << vec.size() << " " << vec.capacity() << endl;
}
return 0;
}
练习 9.39:
首先,reserve为svec分配了1024个元素的空间。随后,循环不断读入字符,添加到svec末尾,直到遇到文件结束符。这个过程中,如果读入的字符串数量不多于1024,则svec的capacity保持不变,不会分配新的内存空间。否则,会按一定规则分配更大的内存空间,并进行字符串的移动。接下来,resize将向svec末尾添加当前字符串数量一半那么多的新字符串,他们的值都是空串。若空间不够,会分配足够容纳这些字符串的内存空间。
练习 9.40:
读入256、512或1000个词,容器的capacity是1048;若读入了1048个词,则resize之后容器的capacity将是2304。
#include<iostream>
using namespace std;
#include<string>
#include<vector>
int main()
{
vector<string> vec;
vec.reserve(1024);
for (int i = 0; i < 1048; ++i)
{
vec.push_back("cpp");
}
vec.resize(vec.size() + vec.size() / 2);
cout << vec.capacity() << endl;
return 0;
}
练习 9.41:
#include<iostream>
using namespace std;
#include<string>
#include<vector>
int main()
{
vector<char> vec{ 'c','p','p' };
string str(vec.begin(), vec.end());
cout << str << endl;
return 0;
}
练习 9.42:
#include<iostream>
using namespace std;
#include<vector>
int main()
{
string s;
char c;
s.reserve(100);
while (cin >> c)
s.push_back(c);
return 0;
}
练习 9.43:
#include<iostream>
using namespace std;
#include<vector>
void replace(string& s, const string& oldVal, const string& newVal)
{
for (auto iter = s.begin(); (s.end() - iter) >= oldVal.size(); ++iter)
{
if (string(iter, iter + oldVal.size()) == oldVal)
{
iter = s.erase(iter, iter + oldVal.size());
iter = s.insert(iter, newVal.begin(), newVal.end());
}
}
}
int main()
{
string str{ "thru tho thru tho." };
replace(str, "thru", "through");
replace(str, "tho", "though");
cout << str << endl;
return 0;
}
练习 9.44:
#include<iostream>
using namespace std;
#include<vector>
void replace(string& s, const string& oldVal, const string& newVal)
{
for (string::size_type i = 0; i != s.size();)
{
if (string(s, i, oldVal.size()) == oldVal)
{
s.replace(i, oldVal.size(), newVal);
i += oldVal.size();
}
else
++i;
}
}
int main()
{
string str{ "thru tho thru tho." };
replace(str, "thru", "through");
replace(str, "tho", "though");
cout << str << endl;
return 0;
}
练习 9.45:
#include<iostream>
using namespace std;
#include<string>
string pre_suffix(const string& name, const string& pre, const string& suf)
{
string ret = name;
ret.insert(ret.begin(), pre.begin(), pre.end());
ret.append(suf);
return ret;
}
int main()
{
cout << pre_suffix("Lee", "Mr.", ",Jr.") << endl;
return 0;
}
练习 9.46:
#include<iostream>
using namespace std;
#include<string>
string pre_suffix(const string& name, const string& pre, const string& suf)
{
string ret = name;
ret.insert(0, pre);
ret.insert(ret.size(), suf);
return ret;
}
int main()
{
cout << pre_suffix("Lee", "Mr.", ",Jr.") << endl;
return 0;
}
练习 9.47:
#include<iostream>
using namespace std;
#include<string>
int main()
{
string numbers("0123456789");
string alphabet("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
string str("ab2c3d7R4E6");
cout << "numeric characters: ";
for (string::size_type pos = 0;
(pos = str.find_first_of(numbers, pos)) != string::npos; ++pos)
cout << str[pos] << " ";
cout << endl;
cout << "alphabetic characters: ";
for (string::size_type pos = 0;
(pos = str.find_first_of(alphabet, pos)) != string::npos; ++pos)
cout << str[pos] << " ";
cout << endl;
return 0;
}
#include<iostream>
using namespace std;
#include<string>
int main()
{
string numbers("0123456789");
string alphabet("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
string str("ab2c3d7R4E6");
cout << "numeric characters: ";
for (string::size_type pos = 0;
(pos = str.find_first_not_of(alphabet, pos)) != string::npos; ++pos)
cout << str[pos] << " ";
cout << endl;
cout << "alphabetic characters: ";
for (string::size_type pos = 0;
(pos = str.find_first_not_of(numbers, pos)) != string::npos; ++pos)
cout << str[pos] << " ";
cout << endl;
return 0;
}
练习 9.48:
返回string::pos
练习 9.49:
#include<iostream>
#include<string>
#include<fstream>
using namespace std;
int main()
{
ifstream ifs("words.txt");
if (!ifs)
{
cout << "No data?" << endl;
return -1;
}
string word, longest_word;
while (ifs >> word)
{
if (word.find_first_not_of("aceimnorsuvwxz") == string::npos &&
word.size() > longest_word.size())
longest_word = word;
}
cout << longest_word << endl;
return 0;
}
练习 9.50:
#include<iostream>
#include<string>
#include<vector>
using namespace std;
int sum_for_stoi(const vector<string>& vec)
{
int sum = 0;
for (auto const& elem : vec)
sum += stoi(elem);
return sum;
}
float sum_for_stof(const vector<string>& vec)
{
float sum = 0;
for (auto const& elem : vec)
sum += stof(elem);
return sum;
}
int main()
{
vector<string> vec = { "1", "2", "3", "4.5" };
cout << sum_for_stoi(vec) << endl;
cout << sum_for_stof(vec) << endl;
return 0;
}
练习 9.51:
#include<iostream>
#include<string>
#include<array>
using namespace std;
class Date
{
public:
Date(): year(0), month(0), day(0){}
Date(const string& str);
void print()
{
cout << month << "-" << day << "-" << year << endl;
}
private:
unsigned year;
unsigned month;
unsigned day;
array<string, 12> month_names{ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
unsigned trans_month(const string& str); // 月份字符串转换
};
Date::Date(const string& str)
{
string delimiters(" ,/");
auto month_day_delim_pos = str.find_first_of(delimiters);
if (month_day_delim_pos == string::npos)
throw invalid_argument("This format is not supported now.");
month = trans_month(str.substr(0, month_day_delim_pos));
auto day_year_delim_pos = str.find_first_of(delimiters, month_day_delim_pos + 1);
auto day_len = day_year_delim_pos - month_day_delim_pos;
day = stoi(str.substr(month_day_delim_pos + 1, day_len));
year = stoi(str.substr(day_year_delim_pos + 1));
}
unsigned Date::trans_month(const string& str)
{
if (str.empty())
return 0;
if (isdigit(str[0]))
return stoi(str);
for (size_t i = 0; i != 12; ++i)
{
if (str.find(month_names[i]) != string::npos)
return i + 1;
}
return 0; // 没找到
}
int main()
{
Date date1("January 1,1900");
date1.print();
Date date2("1/1/1990");
date2.print();
Date date3("Jan 1 1900");
date3.print();
Date date4;
date4.print();
return 0;
}
练习 9.52:
#include<iostream>
#include<string>
#include<stack>
using namespace std;
int main()
{
string expr("This is (Mooophy(awesome)((((wooooooooo))))) and (ocxs) over");
const char repl = '#'; // 代替括号内的运算结果
unsigned seen = 0; // 记录左括号出现次数
stack<char> stk;
for (auto c : expr)
{
stk.push(c);
if (c == '(')
++seen;
// 看到左括号后又看到一个右括号
if (seen && c == ')')
{
while (stk.top() != '(')// pop对象直到左括号
{
stk.pop();
}
stk.pop(); // pop左括号
stk.push(repl); // 替换括号内的运算结果
--seen;
}
}
// 输出
string output;
for (; !stk.empty(); stk.pop())
output.insert(output.begin(), stk.top());
cout << output << endl;
return 0;
}