chapter 9
笔记较为零散,都是自己不熟悉的知识点。
习题答案至于一个.cc 中,需要演示某一题直接修改 #define NUM***, 如运行9.9题为#define NUM99;
1、 string和vector将元素保存在连续的内存中,由于元素是连续存储的,由元素的下标来计算其地址是非常快速的。但是,这两种容器的中间文职添加或删除元素就非常耗时:在一次插入或删除操作后,需要移动插入/删除位置之后的所有元素来保持连续存储。
list和forward_list两个容器的设计目的是令容器任何位置的添加和删除操作都很快捷。作为代价,这两个容器不支持元素的随机访问:为了访问一个元素,我们只能遍历整个容器。且与vector和deque相比,这两个额外内存开销很大。
2、 使用vector是最好的选择。如果不确定,可以只使用vector和list公共的操作:使用迭代器,不使用下标操作,避免随机访问。
迭代器范围的概念是标准库的基础。两个迭代器的元素范围被称为左闭合区间: [begin, end)
将一个新容器床创建为另一个容器的拷贝方法有两种:可以直接拷贝整个容器,或者(array除外)拷贝由一个迭代器对指定的元素的范围。
由于两个迭代器表示一个范围,因此可以使用这种构造函数来拷贝一个容器中的子序列。
3. name.assign(v.begin(),v.end());
assign调用将name中的元素替换为迭代器指定的范围中的元素的拷贝(仅用于顺序容器)。
由于其旧元素被替换,因此传递给assign的迭代器不能指向调用assign的容器。
除了array和forwar_list之外,每个顺序容器包括string都支持push_back。
4. 当我们用一个对象来初始化容器时,或将一个对象插入到容器中,实际放入到容器中的是对象值的拷贝,而不是对象本身。
容器中的元素与提供值的对象之间没有任何关联。
使用insert的返回值,insert返回的迭代器恰好指向这个新元素。
emplace操作,三个成员empalce_front, emplace,emplace_back这些操作构造而不是拷贝元素。分别对应
push_front,insert和push_back。调用push和insert成员函数时, 我们将元素类型的对象传递给它们,这些对象被拷贝到
容器中。而当我们调用一个emplace成员函数时,则是将参数传递给元素类型的构造函数。
5. 下标操作,下标运算符接受一个下标参数,返回容器中该位置的元素的引用。
因为在一个单向链表中,没有简单的方式来获取一个元素的前驱,所以在一个forward_list中添加或删除元素的操作是
通过改变给定元素之后的元素来完成的。这样,我们总是可以访问到被添加或删除操作所影响的元素。
forward_list没有定义insert/emplace/erase,而是定义了insert_after/emplace_after/srase_after的操作。
6. 由于向迭代器添加元素和从迭代器删除元素的代码可能会是迭代器失效,因此必须保证每次改变容器的操作之后都
正确地重新定位迭代器,这个建议对vector/string/deque尤为重要。
不要返回end返回的迭代器。
reserve并不改变容器中元素的数量,它仅影响vector预先分配多大的内存空间。
7. string搜索函数返回string::size_type值,该类型是一个unsigned类型,因此,用一个int或其他带符号类型来保存这些函数的返回值不是一个好主意。
顺序容器适配器:stack/queue/priority_queue。适配器是标准库的一个通用概念,容器、迭代器和函数都有适配器。
适配器是一种机制,使其某种事物的行为看起来像一种不同的类型。
//main.cc
#include <fstream>
#include <iostream>
#include <list>
#include <deque>
#include <vector>
#include <forward_list>
#include <stack>
using namespace std;
#define NUM952
/*9.4*/
bool find(vector<int>::iterator begin, vector<int>::iterator end, int val){
for(vector<int>::iterator iter = begin; iter!= end; ++iter)
if(*iter == val)
return true;
return false;
}
/*9.5*/
vector<int>::iterator find2(vector<int>::iterator begin, vector<int>::iterator end, int val){
for(vector<int>::iterator iter = begin; iter!= end; ++iter)
if(*iter == val)
return iter;
return end;
}
/*9.28*/
void list_input(forward_list<string> &flst, string str1, string str2){
auto prev = flst.before_begin();
for(auto cur = flst.begin();
cur != flst.end(); prev = cur, ++cur)
if(*cur == str1){
flst.insert_after(cur, str2);
return;
}
flst.insert_after(prev, str2);
}
/*9.43*/
void replace1(string &s, const string &oldVal,const string &newVal){
for(auto beg = s.begin(); beg != s.end(); ++beg){
if(*beg != oldVal.front())
continue;
if(distance(beg, s.end()) < distance(oldVal.begin(), oldVal.end()))
break;
if(string{beg, beg + oldVal.size()} == oldVal){
auto pos = distance(s.begin(), beg);
s.erase(beg, beg + oldVal.size());
s.insert(beg, newVal.begin(), newVal.end());
beg = next(s.begin(), pos + newVal.size() -1);
}
}
}
/*9.44*/
void replace2(string &s, const string& oldVal, const string& newVal){
for(string::size_type i = 0; i != s.size(); ++i)
if(s.substr(i, oldVal.size()) == oldVal){
s.replace(i, oldVal.size(), newVal);
i += newVal.size() -1;
}
}
/*9.45*/
string func(const string &name, const string &pre, const string &pos){
string tmp(name); //不能直接对const string直接操作
tmp.append(pos); //tmp.insert(tmp.size(), pos);
tmp.insert(tmp.begin(), pre.begin(), pre.end());
return tmp;
}
/*9.45*/
string func2(const string &name, const string &pre, const string &pos){
string tmp(name); //不能直接对const string直接操作
tmp.insert(tmp.size(), pos);
tmp.insert(0, pre);
return tmp;
}
/*9.50*/
int sum_for_int(const vector<string> &v)
{
int sum = 0;
for (auto const& s : v) sum += stoi(s);
return sum;
}
float sum_for_float(const vector<string> &v)
{
float sum = 0.0;
for (auto const& s : v) sum += stof(s);
return sum;
}
/*9.51*/
class Date{
public:
Date(const string& s);
unsigned year;
unsigned month;
unsigned day;
};
Date::Date(const string& s)
{
unsigned format = 0;
// 1/1/1900
if (s.find_first_of("/") != string::npos) format = 0x10;
// Jan 1, 1900
if (s.find_first_of(",") >= 4 && s.find_first_of(",") != string::npos)
format = 0x01;
switch (format) {
// format = 1/1/1900
case 0x10:
day = stoi(s.substr(0, s.find_first_of("/")));
month = stoi(s.substr(s.find_first_of("/") + 1,
s.find_first_of("/") - s.find_last_of("/")));
year = stoi(s.substr(s.find_last_of("/") + 1));
break;
// format = January 1, 1900 or Jan 1, 1900
case 0x01:
day = stoi(
s.substr(s.find_first_of("1234567890"),
s.find_first_of(",") - s.find_first_of("1234567890")));
if (s.find("Jan") < s.size()) month = 1;
if (s.find("Feb") < s.size()) month = 2;
if (s.find("Mar") < s.size()) month = 3;
if (s.find("Apr") < s.size()) month = 4;
if (s.find("May") < s.size()) month = 5;
if (s.find("Jun") < s.size()) month = 6;
if (s.find("Jul") < s.size()) month = 7;
if (s.find("Aug") < s.size()) month = 8;
if (s.find("Sep") < s.size()) month = 9;
if (s.find("Oct") < s.size()) month = 10;
if (s.find("Nov") < s.size()) month = 11;
if (s.find("Dec") < s.size()) month = 12;
year = stoi(s.substr(s.find_last_of(" ") + 1));
break;
}
}
int main(){
/*9.1*/
#ifdef NUM91
cout <<"(a)vector,因为我们不需要在中间添加或删除元素. (b)deque,因为deque两端添加删除操作很快, 并且不需要在中间添加/删除元素. (c)vector不需要在头尾添加删除元素."<<endl;
#endif
/*9.2*/
#ifdef NUM92
list< deque<int> > li;
#endif
/*9.3*/
#ifdef NUM93
cout <<"begin和end迭代器,begin和end必须指向相同的容器,begin靠自身叠加接近end的位置."<<endl;
#endif
/*9.4*/
#ifdef NUM94
int val(3);
vector<int> vec = {1, 2, 3, 4, 5};
cout << find(vec.begin(), vec.end(), val) <<endl;
#endif
/*9.5*/
#ifdef NUM95
int val(3);
vector<int> vec(10,1);
cout << *find2(vec.begin(), vec.end(), val) <<endl;
#endif
/*9.6*/
#ifdef NUM96
cout <<"运算符‘<’不能用在list迭代器中,修改 while(iter1 != iter2) "<<endl;
#endif
/*9.7*/
#ifdef NUM97
cout<< "vector<int>::size_type "<<endl;
#endif
/*9.8*/
#ifdef NUM98
cout <<"读取list<string>::const iterator, 写入list<string>::iterator "<<endl;
#endif
/*9.9*/
#ifdef NUM99
cout<< "cbegin是const_iterator类型的,begin是iterator类型. "<<endl;
#endif
/*9.10*/
#ifdef NUM910
vector<int> v1;
const vector<int> v2;
auto it1 = v1.begin();
auto it2 = v2.begin(), it3 = v1.cbegin(), it4 = v2.cbegin();
cout << "1.vector<int>::iterator 2/3/4.vector<int>::const_iterator"<<endl;
#endif
/*9.11*/
#ifdef NUM911
vector<int> vec; //0
vector<int> vec1(10); //10个元素0
vector<int> vec2(10, 1); //1个1
vector<int> vec3{1,2,3,4,5}; //1,2,3,4,5
vector<int> vec4(other_vec); //other_vec
vector<int> vec5(other_vec.begin(), other_vec.end()); //other_vec
#endif
/*9.12*/
#ifdef NUM912
cout<<"接收一个容器创建拷贝对象是拷贝其所有元素, 但是接收两个迭代器创建拷贝的构造函数则是拷贝两个迭代器之间的元素: [begin, end) " <<endl;
#endif
/*9.13*/
#ifdef NUM913
vector<int> vec(5,1);
list<int> li(5,2);
vector<double> dec(li.begin(), li.end());
for(auto i : li)
cout << i;
cout <<endl;
for(auto v : dec)
cout << v;
cout <<endl;
//from vector<int> to vector<double>
vector<double> dvec(vec.begin(), vec.end());
for(auto i : vec)
cout << i;
cout <<endl;
for(auto v : dvec)
cout << v;
cout <<endl;
#endif
/*9.14*/
#ifdef NUM914
list<const char*> li = {"c++ & linux"};
vector<string> vec(li.cbegin(), li.cend());
for(auto &i : li)
cout << i; cout <<endl;
for(auto &v : vec)
cout << v; cout <<endl;
#endif
/*9.15*/
#ifdef NUM915
vector<int> vec1 = {1,2,3,4,5}, vec2= {1,2,3,4};
cout << boolalpha << (vec1 == vec2) << endl;
#endif
/*9.16*/
#ifdef NUM916
list<int> li = {1,2,3,4,5};
vector<int> vec1= {1,2,3,4};
vector<int> vec2 = {1,2,3,4,5};
cout << boolalpha << (vector<int>(li.begin(), li.end()) == vec1) << endl;
cout << noboolalpha <<(vector<int>(li.begin(), li.end()) == vec2) << endl;
#endif
/*9.17*/
#ifdef NUM917
cout << "1.c1c2必须是相同类型的容器.2.c1c2的元素必须是相同类型. "<<endl;
#endif
/*9.19*/
#ifdef NUM918
string str;
deque<string> deq;
while(cin >> str)
deq.push_back(str);
for(deque<string>::iterator it = deq.begin(); it != deq.end(); ++it)
cout << *it << " ";
cout <<endl;
#endif
/*9.19*/
#ifdef NUM919
list<string> input;
for(string str; cin >> str; input.push_back(str))
;
for(auto it = input.cbegin(); it != input.cend(); ++it)
cout << *it << " ";
cout <<endl;
#endif
/*9.20*/
#ifdef NUM920
list<int> list1 = {1,2,3,4,5,6,7,8,9};
deque<int> deq1, deq2;
for(auto it = list1.cbegin(); it != list1.cend(); ++it)
if(*it % 2)
deq2.push_back(*it); //odd
else
deq1.push_back(*it); //even
// deque<int> odd, even;
// for (auto i : l) (i & 0x1 ? odd : even).push_back(i);
for(auto &i : deq1)
cout << i <<' ';
cout <<endl;
for(auto &i : deq2)
cout << i <<' ';
cout <<endl;
#endif
/*9.21*/
#ifdef NUM921
string word;
vector<string> vec;
auto iter = vec.begin();
while(cin >> word)
iter = vec.insert(iter, word);
for(auto &i : vec)
cout << i <<" "; cout << endl;
#endif
/*9.22*/
#ifdef NUM922
cout <<"死循环,mid永远不能达到mid, 并且在insert之后,mid就无效了."<<endl;
//fixed
int some_value = 2;
vector<int> iv = {1,2,3,4,5,6,7,8,9};
vector<int>::iterator iter = iv.begin(), mid = iv.begin() + iv.size()/2;
while(iter !=mid){
if(*mid == some_value)
mid = iv.insert(mid, 2*some_value);
else
--mid;
}
for(auto &i : iv)
cout << i <<" "; cout << endl;
#endif
/*9.23*/
#ifdef NUM923
vector<int> c(1,2);
if(!c.empty()){
auto val = *c.begin(), val2 = c.front();
cout << "val: "<<val <<" ";
auto last = c.end();
auto val3 = *(--last);
cout << "val3: "<<val3 <<" ";
auto val4 = c.back();
cout <<"val4: " <<val4<<endl;
}
#endif
/*9.24*/
#ifdef NUM924
vector<int> vec(0);
cout << "vec.at(): "<<vec.at(1)<< " " //out of range
<<" vec[1]: "<< vec[1] <<" " //segmentation fault
<<" vec.front(): "<<vec.front()<<" " //segmentation fault
<<" vec.begin(): " << *vec.begin()<<endl; //segmentation fault
#endif
/*9.25*/
#ifdef NUM925
list<int> lst = {1,2,3,4,5,6,7,8,9};
auto elem1 = lst.begin();
auto elem2 = lst.begin();
lst.erase(elem1, elem2);
cout <<"如果elem1和elem2迭代器相等,什么也不发生."<<endl;
elem1 = lst.end();
elem2 = lst.end();
lst.erase(elem1, elem2);
for(auto &i : lst)
cout << i <<" "; cout << endl;
#endif
/*9.26*/
#ifdef NUM926
int ia[] = {0, 1, 1, 2, 3, 5, 8, 13, 21, 55, 89};
vector<int> vec(ia, end(ia)); //end()
list<int> lst(vec.begin(), vec.end());
for(auto it = lst.begin(); it != lst.end(); ++it)
if(*it % 2)
it = lst.erase(it); //erase(a)返回指向被删除元素之后元素的迭代器
for(auto it = vec.begin(); it != vec.end(); ++it)
if(!(*it %2))
it = vec.erase(it);
for(auto &i : lst)
cout << i <<" "; cout << endl;
for(auto &i : vec)
cout << i <<" "; cout << endl;
#endif
/*9.27*/
#ifdef NUM927
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 & 0x1 )
curr = flst.erase_after(prev);
else {
prev = curr;
++curr;
}
for(auto &i : flst)
cout << i <<" "; cout << endl;
#endif
/*9.28*/
#ifdef NUM928
forward_list<string> flst = {"linux","Nick","Josh"};
list_input(flst, "linux", "&c++");
for(auto &i : flst)
cout << i <<" "; cout << endl;
#endif
/*9.29*/
#ifdef NUM929
vector<int> vec(25);
cout << vec.size() <<endl;
vec.resize(100); //add 75 items
cout << vec.size() <<endl;
vec.resize(10); //erase 90 from the back
cout << vec.size() <<endl;
#endif
/*9.30*/
#ifdef NUM930
cout <<"如果容器包含一个类类型元素,resize增加元素,必须提供元素类型的初始值,或者元素类型必须提供一个构造函数. "<<endl;
#endif
/*9.31*/
#ifdef NUM931
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);
advance(iter,2);
}else
iter = lst.erase(iter);
}
for(auto &i : lst) cout << i <<" ";
cout <<endl;
//forward_list
forward_list<int> flst = {0,1,2,3,4,5,6,7,8,9};
auto prev = flst.before_begin(), it = flst.begin();
while(it!= flst.end()){
if(*it % 2){
it = flst.insert_after(prev, *it);
advance(it, 2);
advance(prev, 2);
}else
it = flst.erase_after(prev);
}
for(auto &i : flst) cout << i <<" ";
cout <<endl;
#endif
/*9.32*/
#ifdef NUM932
vector<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 += 1;
}else
iter = lst.erase(iter);
}
for(auto &i : lst) cout << i <<" ";
cout <<endl;
#endif
/*9.33*/
#ifdef NUM933
vector<int> vec = {0,1,2,3,4,5,6,7,8,9};
auto begin = vec.begin();
while(begin != vec.end()){
++begin;
vec.insert(begin, 42); //程序崩溃,insert的操作无效,begin访问了不存在的内存
++begin;
}
for(auto &i : vec) cout << i <<" ";
cout <<endl;
#endif
/*9.34*/
#ifdef NUM934
vector<int> vec = {0,1,2,3,4,5,6,7,8,9};
auto iter = vec.begin();
while(iter != vec.end()){
if(*iter % 2)
iter = vec.insert(iter, *iter);//无限循环
++iter;
}
for(auto &i : vec) cout << i <<" ";
cout <<endl;
#endif
/*9.35*/
#ifdef NUM935
cout << "size表示容器已经拥有的元素的数量大小. capacity表示在容器扩容之前,容器一共能够拥有多少元素."<<endl;
#endif
/*9.36*/
#ifdef NUM936
cout << "capacity cannot be less than size"<<endl;
#endif
/*9.37*/
#ifdef NUM937
cout << "list链表结构的存储元素并不是连续的,而array的大小是固定的,不能增加元素."<<endl;
#endif
/*9.38*/
#ifdef NUM938
vector<string> vec;
string word = "word";
int size;
while(1){
vec.push_back(word);
size = vec.capacity();
cout<< size<<endl;
if(size > 100)
return 0;
}
#endif
/*9.39*/
#ifdef NUM939
vector<string> svec;
svec.reserve(1024); // 设定capacity初始值 1024
string word;
while (cin >> word)
svec.push_back(word);
svec.resize(svec.size()+svec.size()/2); // 设定capacity初始值 3/2's
#endif
/*9.40*/
#ifdef NUM940
vector<string> svec;
svec.reserve(1024);
string word = "word";
int flag = 0;
while (flag < 1048){ //改变数值,512时capacity1024,1000/2000,1048/2000
svec.push_back(word);
++flag;
}
svec.resize(svec.size()+svec.size()/2);
cout << svec.capacity() <<endl;
#endif
/*9.41*/
#ifdef NUM941
vector<char> vec{'l','i','n','u','x'};
string str(vec.begin(), vec.end());
cout << str << endl;
#endif
/*9.42*/
#ifdef NUM942
string str; char c;
str.reserve(100);
while(cin >> c)
str.insert(str.begin(),c); //stirng不能插入string类型
cout << str <<endl;
cout <<"先reserve足够的空间给string对象."<<endl;
#endif
/*9.43*/
#ifdef NUM943
{
string str{"tho, thru"};
replace1(str, "thru", "through");
replace1(str, "tho", "though");
std::cout << str << std::endl;
}
string str{"thoughtho, thru"};
replace1(str, "thru", "through");
replace1(str, "tho", "though");
std::cout << str << std::endl;
#endif
/*9.44*/
#ifdef NUM944
string str{"tho, thru"};
replace2(str, "tho", "though");
replace2(str, "thru", "through");
cout << str <<endl;
#endif
/*9.45*/
#ifdef NUM945
string name = {"Show"};
cout << func(name, "Mr.", ",Jr") <<endl;
#endif
/*9.46*/
#ifdef NUM946
string name = {"Show"};
cout << func(name, "Mr.", ",Jr") <<endl;
#endif
/*9.47*/
#ifdef NUM947
{ string numbers{"123456789"};
string alphabet{"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"};
string str{"ab2c3d7R4E6"};
cout << "numeric: ";
for(string::size_type pos = 0; (pos = str.find_first_of(numbers, pos))
!= string::npos;++pos){
cout << str[pos] <<" ";
}
cout <<"\nalphabet characters: ";
for(string::size_type pos = 0; (pos = str.find_first_of(alphabet, pos))
!= string::npos;++pos){
cout << str[pos] <<" ";
}
cout <<endl;
}
string numbers{"123456789"};
string alphabet{"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"};
string str{"ab2c3d7R4E6"};
cout << "numeric: ";
for(string::size_type pos = 0; (pos = str.find_first_of(alphabet, pos))
!= string::npos;++pos){
cout << str[pos] <<" ";
}
cout <<"\nalphabet characters: ";
for(string::size_type pos = 0; (pos = str.find_first_of(numbers, pos))
!= string::npos;++pos){
cout << str[pos] <<" ";
}
cout <<endl;
#endif
/*9.48*/
#ifdef NUM948
string name("r2d2"), numbers("0123456789");
cout << numbers.find(name) <<endl;
cout << "返回npos."<<endl;
#endif
/*9.49*/
#ifdef NUM949
ifstream ifs("./test.txt");
string longest_word;
if(!ifs){
cout <<"No text! " <<endl;
return -1;
}
for(string word; ifs >> word; )
if(word.find_first_not_of("aceimnorsuvwxz") == string::npos &&
word.size() > longest_word.size())
longest_word = word;
cout << longest_word <<endl;
#endif
/*9.50*/
#ifdef NUM950
vector<string> vec{"1","2","3.12","4.12"};
cout << sum_for_int(vec) <<endl;
cout << sum_for_float(vec) << endl;
#endif
/*9.51*/
#ifdef NUM951
Date d("99/21/3871");
cout << d.day << " " << d.month << " " << d.year << " "<<endl;
#endif
/*9.52*/
#ifdef NUM952
auto& expr = "This is (Mooophy(awesome)((((wooooooooo))))) and (ocxs) over";
auto repl = '#';
auto seen = 0;
stack<char> stk;
for (auto c : expr) {
stk.push(c);
if (c == '(') ++seen; // open
if (seen && c == ')') { // pop elements down to the stack
while (stk.top() != '(') stk.pop();
stk.pop(); // including the open parenthesis
stk.push(repl); // push a value indicate it was replaced
--seen; // close
}
}
// Test
string output;
for (; !stk.empty(); stk.pop())
output.insert(output.begin(), stk.top());
cout << output << endl; // "This is # and # over"
#endif
return 0;
}
参考资料:
c++ primer中文版第五版,电子工业出版社。
c++ primer第四版习题解答,人民邮电出版社。
pezy@github https://github.com/pezy/CppPrimer