C++ Primer 第九章 顺序容器 3

9.35 解释一下vector的capacity和size有何区别 。

答:容器的size是指它已经保存的元素的数目,而capacity则是在不分配新的内存空间的前提下它最多可以保存多少元素。

9.36 一个容器的capacity会小于他的size吗? 。

答:从上题的定义来看,capacity一定会大于或者等于size。


9.37 为什么list或者array没有capacity函数? 。

答:对于list,只需在尾后直接插入新增元素就可以,插入和删除都很快;array的容量在初始化的时候就已经固定,不能够改变其容量。


9.38 编写程序,探究在你的标准库中,vetor是如何增长的? 。

答:
环境 Windows+ VS2019

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

int main(int argc, char* argv[])
{
	vector<int> ivec;
	cout << ivec.capacity() << " " << ivec.size() << endl;
	for (int n = 0; n < 100; n++)
	{
		for (vector<int>::size_type i = 0; i < n; i++)
		{
			ivec.push_back(i);
		}
		cout << ivec.capacity() << " " << ivec.size() << endl;
		ivec.clear();
	}
	return 0;
}

下图中左边的是容量大小,右边是size. 可以看到vector的容量增长是比前一个容量增长0.5倍,如9*0.5=4.5,去除后面小数,9+4=13.
在这里插入图片描述


9.39 解释下面程序片段做了什么? 。

vector<string> svec;
svec.reserve(1024);
string word;
while (cin >> word)
	svec.pushback(word);
svec.resize(svec.size() + svec.size() / 2);
答:该片段首先声明了一个string元素的vector变量,然后给svec分配能够存储1024个元素的内存空间,填充完元素之后,重新对svec的大小进行调整,调整为原来的3/2。

9.41 编写程序,从一个vector< char>初始化一个string 。

答: .data() 返回内存空间首地址
#include <iostream>
#include <vector>
using namespace std;

int main(int argc, char* argv[])
{
	vector<char> cvec = {'h', 'i', 'y'};
	string s(cvec.data(), cvec.size());
	for (auto i : s)
	{
		cout << i << endl;
	}
	return 0;
}


9.42 假定你希望每次读取一个字符存入一个string中,而且知道最少需要读取100个字符,应该如何提高程序的性能?

答:本题的主要考察内容是学习高效的处理动态增长的string. 首先string组要读取至少100个字符,所以先使用reserve为string分配100个内存空间,然后逐个读取字符,使用push_back添加到string末尾。
#include <iostream>
#include <string>
using namespace std;
void input_string(string& );
int main(int argc, char* argv[])
{
	string s;
	input_string(s);
	for (auto i : s)
	{
		cout << i << endl;
	}
	return 0;
}
void input_string(string& s)
{
	s.reserve(100);
	char c;
	while (cin >> c)
	{
		s.push_back(c);
	}
}


9.43 编写一个函数,接受三个string参数s, oldVal和newVal。使用迭代器及insert和erase函数将s中所有oldVal替换为newVal。测试你的程序,用它替换通用的简写形式,如,将“tho”替换为“though”,将“thru”替换为through。

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

void replace_string(string& str, string& oldStr, string& newStr);

int main(int argc, char* argv[])
{
	string str = "cdethoabc";
	string oldStr = "tho";
	string newStr = "though";
	replace_string(str, oldStr, newStr);
	for (auto i : str)
	{
		cout << i << endl;
	}
	return 0;
}

void replace_string(string& str, string& oldStr, string& newStr)
{
	if (oldStr.empty())
	{
		return;
	}
	auto oldStrIter = oldStr.begin();
	auto strIter = str.begin();
	auto l = oldStr.size();
	int num = 0;
	while (oldStrIter != oldStr.end() && strIter != str.end())
	{
		if (*oldStrIter == *strIter)
		{
			oldStrIter++;
			strIter++;
			num++;
		}
		else
		{
			strIter++;
			num = 0;
		}
	}
	if (num != l)
	{
		cout << "Can't find the old substring!" << endl;
		return;
	}
	auto iter = str.erase(strIter-l, strIter); // 返回最后一个被删除元素之后元素的迭代器
	for (auto c : newStr)
	{
		iter = str.insert(iter, c); // 返回指向第一个插入字符的迭代器
		iter++;
	}
}

9.44重写上一题的函数,这次使用一个下标和replace。

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

void replace_string(string& str, string& oldStr, string& newStr);

int main(int argc, char* argv[])
{
	string str = "cdethoabc";
	string oldStr = "tho";
	string newStr = "though";
	replace_string(str, oldStr, newStr);
	for (auto i : str)
	{
		cout << i << endl;
	}
	return 0;
}

void replace_string(string& str, string& oldStr, string& newStr)
{
	if (oldStr.empty())
	{
		return;
	}
	auto oldStrIter = oldStr.begin();
	auto strIter = str.begin();
	auto l = oldStr.size();
	int num = 0;
	while (oldStrIter != oldStr.end() && strIter != str.end())
	{
		if (*oldStrIter == *strIter)
		{
			oldStrIter++;
			strIter++;
			num++;
		}
		else
		{
			strIter++;
			num = 0;
		}
	}
	if (num != l)
	{
		cout << "Can't find the old substring!" << endl;
		return;
	}
	
	auto len = oldStr.length();
	auto index = strIter - str.begin() - len;
	str.replace(index, len, newStr);
}

9.45 编写一个函数,接受一个表示名字的string参数和两个分别表示前缀(Mr.或Ms.)和后缀(如Jr.或III)的字符串。使用迭代器及insert和append函数将前缀和后缀添加到给定的名字中,将生成的新string返回。

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

void name_string(string& name, const string& prefix, const string& suffix);

int main(int argc, char* argv[])
{
	string name = "Zhao";
	string prefix = "Mr.";
	string suffix = "Jr.";
	name_string(name, prefix, suffix);
	for (auto i : name)
	{
		cout << i ;
	}
	return 0;
}

void name_string(string& name, const string& prefix, const string& suffix)
{
	name.insert(name.begin(), 1, ' ');
	name.insert(name.begin(), prefix.begin(), prefix.end());
	name.append(" ");
	name.append(suffix.begin(), suffix.end());
}

9.46 重写上一题的函数,这次使用位置和长度来管理string,并只使用insert。

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

void name_string(string& name, const string& prefix, const string& suffix);

int main(int argc, char* argv[])
{
	string name = "Zhao";
	string prefix = "Mr.";
	string suffix = "Jr.";
	name_string(name, prefix, suffix);
	for (auto i : name)
	{
		cout << i ;
	}
	return 0;
}

void name_string(string& name, const string& prefix, const string& suffix)
{
	name.insert(0, " ");
	name.insert(0, prefix);
	name.insert(name.size(), " ");
	name.insert(name.size(), suffix);
}

9.47 编写程序,首先查找string "abc2def3ghj5"中的数字字符,然后查找其中每个字母字符。编写两个版本程序,第一个版本程序使用find_first_of,第二个版本使用find_first_not_of.

答:
#include <iostream>
#include <string>
#include <list>

void string_find_first_of(const std::string&, const std::string&, 
	std::string::size_type);
void string_find_first_not_of(const std::string&, const std::string&, 
	std::string::size_type);

int main(int argc, char* argv[])
{
	std::string str("abc2def3ghi5");
	std::string s_numbers("0123456789");
	std::string s_char("abcdefghi");

	std::string::size_type pos = 0;
	std::cout << "use find_first_of " << std::endl;
	string_find_first_of(str, s_numbers, pos);
	string_find_first_of(str, s_char, pos);
	std::cout << "use find_first_not_of "<< std::endl;
	string_find_first_not_of(str, s_numbers, pos);
	string_find_first_not_of(str, s_char, pos);

	return 0;
}

void string_find_first_of(const std::string& str, const std::string& sub_string, 
	std::string::size_type pos)
{
	while ((pos = str.find_first_of(sub_string, pos))
		!= std::string::npos)
	{
		std::cout << "Find object at index: " << pos
			<< "  element is " << str[pos] << std::endl;
		++pos;
	}
}

void string_find_first_not_of(const std::string& str, const std::string& sub_string, 
	std::string::size_type pos)
{
	std::list<std::string::size_type> szList;

	while ((pos = str.find_first_not_of(sub_string, pos))
		!= std::string::npos)
	{
		szList.push_back(pos);
		++pos;
	}

	std::list<std::string::size_type>::iterator begin = szList.begin();

	for (int i = 0; i < str.length(); i++)
	{
		if (begin != szList.end())
		{
			if (i != *begin)
			{
				std::cout << "Find object at index: " << i
					<< "  element is " << str[i] << std::endl;
			}
			else
			{
				begin++;
			}
		}
		else
		{
			std::cout << "Find object at index: " << i
				<< "  element is " << str[i] << std::endl;
		}
	}
}

输出结果
在这里插入图片描述


9.48 假定 names 和 numbers的定义如325页所示,numbers.find(name)返回的值是什么?

答:本题主要考察的是find与find_first_of以及find_first_not_of的区别。find寻找的是整个子字符串,后两者只需要寻找到第一个字符出现的位置即可,因此325页,numbers.find(name)返回npos。

9.49 如果一个字母延伸到中线之上,如d或f,则称其有上出头部分(ascender)。如果一个字母延伸到中线之下,如p或q,则称其有下出头部分(descender)。编写程序,读入一个单词文件,输出最长的既不包含上出头部分,也不包含下出头部分的单词。

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

void find_longest_word(ifstream& in);
int main(int argc, char* argv[])
{
	ifstream in("Words.txt");
	find_longest_word(in);
	return 0;
}

void find_longest_word(ifstream& in)
{
	string s, longest_word;
	string as_des_char = "bdfghjklpqty";
	string::size_type pos = 0;
	int max_length = 0;
	while (in >> s)
	{
		if (pos = s.find_first_of(as_des_char) != string::npos)
		{
			continue;
		}
		cout << s << " " << endl;
		if (max_length < s.size())
		{
			max_length = s.size();
			longest_word = s;
		}	
	}
	cout << "最长单词(去除上出头与下出头)  " << longest_word << endl;
}



9.50 编写一个程序处理一个vectro,容器中元素都是整型值,求其元素之和。修改程序,获得浮点型元素之和

#include <iostream>
#include <string>
#include <vector>

using namespace std;

int main(int argc, char* argv[])
{
	vector<string> svec = { "1", "2", "3", "4", "9" };
	int sum_int = 0;
	double sum_dou = 0.0;
	vector<string>::iterator begin = svec.begin();
	while (begin != svec.end())
	{
		int i = stoi(*begin);
		sum_int += i;
		double d = stod(*begin);
		sum_dou += d;
		begin++;
	}
	cout << to_string(sum_int) << endl;
	cout << to_string(sum_dou) << endl;
	return 0;
}



9.51 设计一个类,它有三个unsigned成员, 分别表示年月日。为其编写构造函数,接受一个表示日期的string参数。你的构造函数应该能处理不同数据格式,如January 1,1990、1/1/1990、Jan 1 1900等

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

class TimeClass
{
public:
	unsigned year, month, day;
	TimeClass(string s);
};

TimeClass::TimeClass(string s)
{
	string numbers = { "0123456789" };
	const vector<string> months = {"January", "February", "March", "April", 
		"May","June", "July", "August", "September", "October", "November", "December" };
	const vector<string> sub_months = { "Jan", "Feb", "Mar", "Apr",
		"May","Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
	string::size_type pos;
	if ((pos = s.find_first_of('/')) != string::npos)
	{
		string::size_type pos_last = s.find_last_of('/');
		month = stoi(s.substr(0, pos));
		day = stoi(s.substr(pos + 1, pos_last - 1));
		year = stoi(s.substr(pos_last +1, s.size() - pos_last -1));
	}
	else if ((pos = s.find_first_of(',')) != string::npos)
	{
		string::size_type pos1 = s.find_first_of(numbers);
		day = stoi(s.substr(pos1, pos - 1));
		string sub_str = s.substr(0, pos1 - 1);
		string::size_type pos2;
		int index = 0;
		for (auto i : months)
		{
			index++;
			if ((pos2 = i.find(sub_str)) != string::npos)
			{
				month = index;
				break;
			}
		}
		year = stoi(s.substr(pos + 1, s.size() - pos - 1));
	}
	else if((pos = s.find_first_of(' ')) != string::npos)
	{
		string::size_type pos_last = s.find_last_of(' ');
		day = stoi(s.substr(pos + 1, pos_last - 1));
		string sub_str = s.substr(0, pos);
		string::size_type pos2;
		int index = 0;
		for (auto i : sub_months)
		{
			index++;
			if ((pos2 = i.find(sub_str)) != string::npos)
			{
				month = index;
				break;
			}
		}
		year = stoi(s.substr(pos_last + 1, s.size() - pos_last - 1));
	}

}

int main()
{
	string s1 = "11/6/2019";
	string s2 = "November 26, 2019";
	string s3 = "Nov 26 2019";
	TimeClass timeClass(s2);
	cout << timeClass.month << endl;
	cout << timeClass.day << endl;
	cout << timeClass.year << endl;

	return 0;
}



9.52 使用stack处理括号话的表达式。当你看到一个左括号,将其记录下来。当你在看到一个左括号之后看到一个右括号,从stack中pop对象,知道遇到左括号,将左括号也一起弹出栈。然后将一个值(括号内的运算结果)push到栈中,表示一个括号化的(子)表达式已经处理完毕,被其运算结果代替。

发布了38 篇原创文章 · 获赞 29 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/ruotianxia/article/details/103078325