C++ Primer 中文第 5 版练习答案 第 9 章 顺序容器

C++ Primer 中文版(第 5 版)练习解答合集

自己写的解答,如有错误之处,烦请在评论区指正!


1

(a)如果插入过程不重要:先用 vector 接收所有数据,然后用 sort 排序。如果插入过程重要:用 list,在中间插入的时间复杂度是 O(1)

(b)deque,在两端插入、删除都是 O(1)

(c)先用 vector 接收所有数据,然后用 sort 排序

2

list<deque<int>> testList;

3

  • 它们指向同一个容器中的元素,或者是容器最后一个元素之后的位置
  • end 不在 begin 之前

4

bool findBetween(vector<int>::const_iterator begin, vector<int>::const_iterator end, int target) {
	for (auto p = begin; p != end; ++p) {
		if (*p == target) {
			return true;
		}
	}
	return false;
}

5

// 返回end迭代器表示没有找到 
vector<int>::iterator findBetween(vector<int>::iterator begin, vector<int>::iterator end, int target) {
	for (auto p = begin; p != end; ++p) {
		if (*p == target) {
			return p;
		}
	}
	return end;
}

6

while 循环的条件应该是 iter1 != iter2

某些容器,如 list 不支持 < 运算符,因为数据在内存中的排列不是连续的。

7

注意是索引。

vector<int>::size_type i;

8

list<string>::const_iterator it;
list<string>::iterator cit;

9

begin 返回的迭代器类型是 Typename::iterator

cbegin 返回的迭代器类型是 Typename::const_iterator,不能通过这种迭代器来修改容器内元素

10

变量名类型
it1vector<int>::iterator
it2vector<int>::const_iterator
it3vector<int>::const_iterator
it4vector<int>::const_iterator

11

#include <iostream>
#include <vector>
using namespace std;

void display(const vector<int>& vec) {
	for (auto num : vec) {
		cout << num << " ";
	}
	cout << endl;
}

int main() {
    // empty
	vector<int> vec1;
    // {0, 1, 2, 3, 4}
	vector<int> vec2{0, 1, 2, 3, 4};
    // {0, 1, 2, 3, 4}
	vector<int> vec3(vec2);
    // {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
	vector<int> vec4(10);
    // {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
	vector<int> vec5(10, 1);
    // {2, 3, 4}
	vector<int> vec6(vec2.begin() + 2, vec2.end());
	return 0;
}

12

对于接受一个容器创建拷贝的构造函数,容器类型必须完全相同。但是对于接受两个迭代器创建拷贝的构造函数,容器类型不一定完全相同,只要元素能转换为要初始化的容器的类型就可以。

13

#include <iostream>
#include <vector>
#include <list>
using namespace std;

int main() {
	list<int> lst;
	for (int i = 0; i < 10; ++i)
		lst.emplace_back(i);
	vector<int> vec{1, 2, 3};
	vector<double> vec1(lst.begin(), lst.end());
	vector<double> vec2(vec.begin(), vec.end());
	return 0;
}

14

#include <iostream>
#include <string>
#include <vector>
#include <list>
using namespace std;

int main() {
	list<char*> lst;
	char *p = "12345";
	char *q = "23456";
	lst.emplace_back(p);
	lst.emplace_back(q);
	vector<string> vec;
	vec.assign(lst.begin(), lst.end());
	for (const auto& str : vec)
		cout << str << endl;
	return 0;
}

15

template<class T>
bool operator == (const vector<T>& vec1, const vector<T>& vec2) {
	int size1 = vec1.size(), size2 = vec2.size();
	if (size1 != size2)
		return false;
	for (int i = 0; i != size1; ++i) {
		if (vec1[i] != vec2[i])
			return false;
	}
	return true;
}

16

template<class T>
bool operator == (const vector<T>& vec, const list<T>& lst) {
	int size1 = vec.size(), size2 = lst.size();
	if (size1 != size2)
		return false;
	auto itv = vec.begin();
	auto itl = lst.begin();
	for (; itv != vec.end(); ++itv, ++itl) {
		if (*itv != *itl)
			return false;
	}
	return true;
}

template<class T>
bool operator == (const list<T>& lst, const vector<T>& vec) {
	return vec == lst;
}

17

容器内元素的类型要支持 < 运算符。

18

#include <iostream>
#include <string>
#include <deque>
using namespace std;

int main() {
	string buffer;
	deque<string> words;
	while (cin >> buffer) {
		words.emplace_back(buffer);
	}
	for (deque<string>::const_iterator it = words.begin();
			it != words.end(); ++it)
		cout << *it << endl;
	return 0;
}

19

#include <iostream>
#include <string>
#include <list>
using namespace std;

int main() {
	string buffer;
    // 修改类型
	list<string> words;
	while (cin >> buffer) {
		words.emplace_back(buffer);
	}
    // 修改类型
	for (list<string>::const_iterator it = words.begin();
			it != words.end(); ++it)
		cout << *it << endl;
	return 0;
}

20

#include <iostream>
#include <deque>
#include <list>
using namespace std;

template<class T>
void displayDeque(const deque<T>& deq) {
	for (const auto& num : deq) {
		cout << num << " ";
	}
	cout << endl;
}

int main() {
	list<int> source{1, -99, 0, 8, 678, 99999, 3, 0};
	deque<int> even, odd;
	for (const auto& num : source) {
		if (num % 2) {
			odd.emplace_back(num);
		} else {
			even.emplace_back(num);
		}
	}
	displayDeque(even);
	displayDeque(odd);
	return 0;
}

21

循环可以正常运作,但是效率会很低。每次在 vector 头部插入的时间复杂度是 O(n),插入 n 个元素的时间复杂度是 O(n^2)

22

while 循环中 iter 的位置永远不变,可能会死循环。代码修改如下:

#include <iostream>
#include <vector>
using namespace std;

template<class T>
void displayVec(const vector<T>& deq) {
	for (const auto& num : deq) {
		cout << num << " ";
	}
	cout << endl;
}

int main() {
	int some_val = -99;
	vector<int> iv{1, -99, 0, 8, 678, 99999, 3, 0};
	vector<int>::iterator iter = iv.begin(), 
						  mid = iv.begin() + iv.size()/2;
	while (iter != mid) {
		if (*iter == some_val)
			iter = iv.insert(iter, 2 * some_val) + 1;
		++iter;
	}
	displayVec(iv);
	return 0;
}

23

四个值相等,全部都是 c 中唯一元素的值。

24

#include <iostream>
#include <vector>
using namespace std;

int main() {
	vector<int> evec;
    // 报错std::out_of_range
	cout << evec.at(0) << endl;
    // 以下都会导致程序非正常退出
	cout << evec[0] << endl;
	cout << evec.front() << endl;
	cout << *evec.begin() << endl;
	return 0;
}

25

如果 elem1 和 elem2 相同,且 elem1 不是尾后迭代器,那么就只删除 elem1 指向的元素。

如果 elem2 是尾后迭代器,就删除 elem1 开始,包括 elem1 在内的所有元素。

如果 elem1 和 elem2 都是尾后迭代器,则行为未定义。

26

#include <iostream>
#include <vector>
#include <list>
using namespace std;

void displayVec(const vector<int>& vec) {
	for (auto num : vec)
		cout << num << " ";
	cout << endl;
}

void displayLst(const list<int>& lst) {
	for (auto num : lst)
		cout << num << " ";
	cout << endl;
}

int main() {
	int ia[] = {0, 1, 1, 2, 3, 5, 8, 13, 21, 55, 89};
	int size = sizeof(ia) / sizeof(ia[0]);
	vector<int> vec(ia, ia + size);
	list<int> lst(ia, ia + size);
	
	vector<int>::iterator vit = vec.begin();
	while (vit != vec.end()) {
		if (!((*vit) % 2)) {
			vit = vec.erase(vit);
		} else {
			++vit;
		}
	}
	displayVec(vec);
	
	list<int>::iterator lit = lst.begin();
	while (lit != lst.end()) {
		if ((*lit) % 2) {
			lit = lst.erase(lit);
		} else {
			++lit;
		}
	}
	displayLst(lst);
	return 0;
}

27

#include <iostream>
#include <forward_list>
using namespace std;

void deleteOdd(forward_list<int>& lst) {
	forward_list<int>::iterator prev = lst.before_begin();
	forward_list<int>::iterator curr = lst.begin();
	while (*curr) {
		if ((*curr) % 2) {
			curr = lst.erase_after(prev);
		} else {
			prev = curr;
			++curr;
		}
	}
} 

void displayFlist(const forward_list<int>& lst) {
	for (auto num : lst) {
		cout << num << " ";
	}
	cout << endl;
}

int main() {
	forward_list<int> lst{1, -197, -2, 0, 3, 3357, 888, 89};
	deleteOdd(lst);
	displayFlist(lst);
	return 0;
}

28

#include <iostream>
#include <string>
#include <forward_list>
using namespace std;

template<class T>
void insertAfter(forward_list<T>& lst, const T& target, const T& newStr) {
	typename forward_list<T>::iterator prev = lst.before_begin();
	typename forward_list<T>::iterator curr = lst.begin();
	while (curr != lst.end()) {
		if(*curr == target) {
			lst.insert_after(curr, newStr);
			return;
		}
		prev = curr;
		++curr;
	}
	lst.insert_after(prev, newStr);
} 

template<class T>
void displayFlist(const forward_list<T>& lst) {
	for (auto ele : lst) {
		cout << ele << " ";
	}
	cout << endl;
}

int main() {
	forward_list<string> lst{"Apple", "Bee", "Dog"};
	insertAfter(lst, string("Bee"), string("Cat"));
	displayFlist(lst);
	return 0;
}

29

将 vec 的大小变成 100,并自动在原来的 vec 后面添加 75 个值为 0 的元素。

将 vec 的大小变成 10,并删除后面的 90 个元素。

30

需要元素有默认构造函数,可能会在自动添加元素的时候被调用。

31

首先,list 和 forward_list 的迭代器不支持和整数类型相加,因为这两种容器的元素在内存中不是连续排列的;

其次。forward_list 容器对元素的插入和删除和一般的顺序容器不同,有自己的接口。

#include <iostream>
#include <vector>
#include <list>
#include <forward_list>
using namespace std;

void displayVec(const vector<int>& vec) {
	for (auto num : vec)
		cout << num << " ";
	cout << endl;
}

void displayLst(const list<int>& lst) {
	for (auto num : lst)
		cout << num << " ";
	cout << endl;
}

void displayFlst(const forward_list<int>& flst) {
	for (auto num : flst)
		cout << num << " ";
	cout << endl;
}

int main() {
	vector<int> vec{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
	auto itv = vec.begin();
	while (itv != vec.end()) {
		if (*itv % 2) {
			itv = vec.insert(itv, *itv);
			itv += 2;
		} else {
			itv = vec.erase(itv);
		}
	}
	displayVec(vec);
	
	list<int> lst{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
	auto itl = lst.begin();
	while (itl != lst.end()) {
		if (*itl % 2) {
			itl = lst.insert(itl, *itl);
			++itl;
			++itl;
		} else {
			itl = lst.erase(itl);
		}
	}
	displayLst(lst);
	
	forward_list<int> flst{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
	auto prev = flst.before_begin();
	auto curr = flst.begin();
	while (curr != flst.end()) {
		if (*curr % 2) {
			flst.insert_after(curr, *curr);
			++curr;
			prev = curr;
			++curr;
		} else {
			++curr;
			flst.erase_after(prev);
		}
	}
	displayFlst(flst);
	return 0;
}

32

不合法。因为 insert 成员函数的参数中包含了 *iter++,如果是从右往左计算实参并传参的话就会出错。

33

程序崩溃。begin 迭代器在容器插入元素之后就失效了。

34

#include <iostream>
#include <vector>
#include <list>
#include <forward_list>
using namespace std;

void displayVec(const vector<int>& vec) {
	for (auto num : vec)
		cout << num << " ";
	cout << endl;
}

int main() {
	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 += 2;
		} else {
			++iter;
		}
	}
	displayVec(vec);
	return 0;
}

35

capacity 是指 vector 目前在内存中最多可以使用的大小,一旦 vector 的实际大小大于这个值,就需要重新申请一块更大的连续内存。

size 就是目前 vector 实际的大小。

36

不可能。因为 vector 中所有元素在内存中连续排列,size 大于 capacity 的话放不下(此时 vector 就会申请更大的空间)。

37

因为 list 和 array 中的元素可以在内存中不连续地分布,理论上可以占满所有可用的内存。

38

#include <iostream>
#include <vector>
using namespace std;

void display(const vector<int>& vec) {
	cout << "vec.size(): " << vec.size() << endl;
	cout << "vec.capacity(): " << vec.capacity() << endl;
}

int main() {
	vector<int> vec;
	display(vec);
	vec.push_back(1);
	display(vec);
	vec.push_back(1);
	display(vec);
	vec.push_back(1);
	display(vec);
	vec.insert(vec.end(), 10, 10);
	display(vec);
	vec.insert(vec.end(), 100, 10);
	display(vec);
	vec.insert(vec.end(), 911, 10);
	display(vec);
	vec.push_back(1);
	display(vec);
	return 0;
} 

输出如下:

vec.size(): 0 vec.capacity(): 0
vec.size(): 1 vec.capacity(): 1
vec.size(): 2 vec.capacity(): 2
vec.size(): 3 vec.capacity(): 4
vec.size(): 13 vec.capacity(): 13
vec.size(): 113 vec.capacity(): 113
vec.size(): 1024 vec.capacity(): 1024
vec.size(): 1025 vec.capacity(): 2048

39

构造了一个空的 string 的 vector,svec

将 svec 的 capacity 变成 1024

不断从标准输入中读入 string,添加到 svec 的尾部

将 svec 的大小变为原来的 1.5 倍,多出来的位置用空 string 填充

40

读入 256:resize 之后的 capacity 是 1024

读入 512:resize 之后的 capacity 是 1024

读入 1000:resize 之后的 capacity 大于等于 1500,可能是 1500 或者 2048

读入 1048:resize 之后的 capacity 大于等于 1572,可能是 1572 或者 2048

41

#include <iostream>
#include <vector>
#include <string>
using namespace std;

int main() {
	vector<char> vec{'h', 'e', 'l', 'l', 'o'};
	string s(vec.data(), vec.size());
	cout << s << endl;
	return 0;
} 

42

string s;
s.reserve(100);

43

TDM-GCC 4.9.2 的 string::insert 函数不返回迭代器,于是只好暂存 p 的位置,插入结束后再自行复位。

搜了一下,StackOverflow 上的解释:GCC 4.9 中关于 string 的实现不遵循 C++11,这只是其中一例。

#include <iostream>
#include <string>
using namespace std;

void replaceStr(string& s, const string& oldVal, const string& newVal) {
	int sizeO = oldVal.size(), sizeN = newVal.size();
	string::iterator p = s.begin();
	while (p != s.end()) {
		if (s.substr(p - s.begin(), sizeO) == oldVal) {
			string::difference_type diff = distance(s.begin(), p);
			p = s.erase(p, p + sizeO);
			s.insert(p, newVal.cbegin(), newVal.cend());
			p = s.begin() + diff + sizeN;
		} else {
			++p;
		}
	}
}

int main() {
	string str("sdfsdfthoksdh tho skdthththhftho");
	replaceStr(str, "tho", "though");
	cout << str << endl;
	return 0;
}

44

#include <iostream>
#include <string>
using namespace std;

void replaceStr(string& s, const string& oldVal, const string& newVal) {
	int sizeO = oldVal.size(), sizeN = newVal.size();
	auto p = s.begin();
	while (p != s.end()) {
		if (s.substr(p - s.begin(), sizeO) == oldVal) {
			string::size_type tempPos = p - s.begin();
			s.replace(p, p + sizeO, newVal.begin(), newVal.end());
			p = s.begin() + tempPos + sizeN;
		} else {
			++p;
		}
	}
}

int main() {
	string str("kasdhfj tho th sdfadftho");
	replaceStr(str, "tho", "though");
	cout << str << endl;
	return 0;
}

45

#include <iostream>
#include <string>
using namespace std;

string addPrefixSuffix(const string& name, const string& prefix, const string& suffix) {
	string ret = name;
	ret.insert(ret.begin(), prefix.begin(), prefix.end());
	ret.append(suffix);
	return ret;
}

int main() {
	string name = addPrefixSuffix("Alex", "Mr.", "III");
	cout << name << endl;
	return 0;
}

46

#include <iostream>
#include <string>
using namespace std;

string addPrefixSuffix(const string& name, const string& prefix, const string& suffix) {
	string ret = name;
	ret.insert(0, prefix);
	ret.insert(ret.size(), suffix);
	return ret;
}

int main() {
	string name = addPrefixSuffix("Alex", "Mr.", "III");
	cout << name << endl;
	return 0;
}

47

#include <iostream>
#include <string>
using namespace std;

void displayNumber(const string& str) {
	const string number("0123456789");
	string::size_type pos = 0;
	while ((pos = str.find_first_of(number, pos)) != string::npos) {
		cout << "found number at index: " << pos << endl
			 << "element is: " << str[pos] << endl;
		++pos;
	}
}

void displayAlpha(const string& str) {
	const string number("0123456789");
	string::size_type pos = 0;
	while ((pos = str.find_first_not_of(number, pos)) != string::npos) {
		cout << "found alphabet at index: " << pos << endl
			 << "element is: " << str[pos] << endl;
		++pos;
	}
}

int main() {
	const string str("ab2c3d7R4E6");
	displayNumber(str);
	displayAlpha(str);
	return 0;
}

48

string::npos

49

#include <iostream>
#include <fstream>
#include <string>
using namespace std;

int main() {
	const string ascAndDesc("qtyipdfghjklb");
	ifstream input("words.d");
	string buffer, ans;
	while (input >> buffer) {
		if (buffer.find_first_of(ascAndDesc) == string::npos) {
			if (buffer.size() > ans.size()) {
				ans = buffer;
			}
		}
	}
	cout << ans;
	return 0;
}

50

#include <iostream>
#include <vector>
#include <string>
using namespace std;

int sumVecInt(const vector<string>& vecInt) {
	int sum = 0;
	for (const auto& str : vecInt) {
		sum += stoi(str);
	}
	return sum;
}

double sumVecDbl(const vector<string>& vecDbl) {
	double sum = 0;
	for (const auto& str : vecDbl) {
		sum += stod(str);
	}
	return sum;
}

int main() {
	vector<string> vecInt{"1", "2", "4", "8", "16"};
	cout << sumVecInt(vecInt) << endl;
	
	vector<string> vecDbl{"0.01", "0.02", "0.04", "0.08", "0.16"};
	cout << sumVecDbl(vecDbl) << endl;
	return 0;
}

51

#include <iostream>
#include <sstream>
#include <string>
#include <cctype>
#include <vector>
#include <unordered_map>
using namespace std;

class Date {
public:
	Date() = default;
	Date(const string& date) {
		if (date.empty())
			return;
		string::const_iterator p = date.begin();
		while (delimiters.find(*p) == string::npos)
			++p;
		string monthStr(date.substr(0, p - date.begin()));
//		cout << monthStr << endl;
		if (monthStr.empty()) {
			cerr << "invalid input format." << endl;
			return;
		} else if (isdigit(monthStr[0])) {
			month = stoi(monthStr);
		} else {
			for (auto& ch : monthStr)
				ch = tolower(ch);
			if (stringToMonth.find(monthStr) != stringToMonth.end()){
				month = stringToMonth[monthStr];
			} else {
				cerr << "invalid input format." << endl;
				return;
			}
		}
		
		while (delimiters.find(*p) != string::npos)
			++p;
		string::size_type dayBegin = distance(date.begin(), p);
		while (delimiters.find(*p) == string::npos)
			++p;
		day = stoi(date.substr(dayBegin, distance(date.begin(), p)));
		
		while (delimiters.find(*p) != string::npos)
			++p;
		string::size_type yearBegin = distance(date.begin(), p);
		while (delimiters.find(*p) == string::npos)
			++p;
		year = stoi(date.substr(yearBegin, distance(date.begin(), p)));
	}
	
	void display() {
		cout << "year: "  << year  << " "
			 << "month: " << month << " "
			 << "day: "	  << day   << endl;
	}
	
private:
	unsigned year;
	unsigned month;
	unsigned day;
	// delimiters of the input string
	const string delimiters = " ,/";
	unordered_map<string, int> stringToMonth{
		{"january",		1},
		{"february",	2},
		{"march",		3},
		{"april",		4},
		{"may",			5},
		{"june",		6},
		{"july",		7},
		{"august",		8},
		{"september",	9},
		{"october",		10},
		{"november",	11},
		{"december",	12},
		{"jan",	1},
		{"feb",	2},
		{"mar",	3},
		{"apr",	4},
//		{"may",	5},	// same as above 
		{"jun",	6},
		{"jul",	7},
		{"aug",	8},
		{"sep",	9},
		{"oct",	10},
		{"nov",	11},
		{"dec",	12},
	};
};

int main() {
	Date date1("January 1,1900");
	date1.display();
	Date date2("1/1/1900");
	date2.display();
	Date date3("Jan 1 1900");
	date3.display();
	return 0;
}

52

#include <iostream>
#include <sstream>
#include <string>
#include <cctype>
#include <vector>
#include <stack>
#include <unordered_map>
using namespace std;

unordered_map<string, int> stringToPriority{
	{"(", -1},
	{"+", 0}, {"-", 0},
	{"*", 1}, {"/", 1},
};

string infixToPostfix(const string& infix) {
	string postfix, buffer;
	istringstream input(infix);
	stack<string, vector<string> > ops;
	while (input >> buffer) {
		if (isdigit(buffer[0]) || (buffer[0] == '-' && buffer.size() > 1)) {
			postfix.append(buffer + " ");
		} else if (buffer == "(") {
			ops.push(buffer);
		} else if (buffer == ")") {
			while (!ops.empty() && ops.top() != "(") {
				postfix.append(ops.top() + " ");
				ops.pop();
			}
			ops.pop();
		} else {
			while (!ops.empty() && stringToPriority[ops.top()]
								>= stringToPriority[buffer]) {
				postfix.append(ops.top() + " ");
				ops.pop();
			}
			ops.push(buffer);
		}
	}
	while (!ops.empty()) {
		postfix.append(ops.top() + " ");
		ops.pop();
	}
	return postfix;
}

int calculatePostfix(const string& postfix) {
	stack<int, vector<int> > nums;
	istringstream input(postfix);
	string buffer;
	while (input >> buffer) {
		if (isdigit(buffer[0]) || (buffer[0] == '-' && buffer.size() > 1)) {
			nums.push(stoi(buffer));
		} else {
			int b = nums.top();
			nums.pop();
			int a = nums.top();
			nums.pop();
			switch(buffer[0]) {
				case '+':
					nums.push(a + b);
					break;
				case '-':
					nums.push(a - b);
					break;
				case '*':
					nums.push(a * b);
					break;
				case '/':
					nums.push(a / b);
					break;
			}
		}
	}
	return nums.top();
}

int main() {
	// suppose that the numbers and symbols
	// in the input string are separated by space
	string infix("( ( 10 * ( 6 / ( ( 9 + 3 ) * -11 ) ) ) + 17 ) + 5");
	string postfix = infixToPostfix(infix);
	cout << postfix << endl;
	cout << calculatePostfix(postfix) << endl;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值