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到栈中,表示一个括号化的(子)表达式已经处理完毕,被其运算结果代替。。