C++Prime 第九章后22题
练习9.31
因为list只可以一次一次递增,不可以使用符合赋值运算符,而forward则更笨没有insert和erase,有insert_after和erase_after
修改:
int main()
{
list<int> a{ 1,2,3,4,5,6,7,8,9 };
print(a);
auto iter = a.begin();
while (iter != a.end())//稍作修改,复制偶数,删除奇数.
{
if (*iter % 2)
iter = a.erase(iter);
else
{
iter = a.insert(iter, *iter);
++iter;//list不可使用复合赋值运算符
++iter;//advance(iter,2)也可
}
}
print(a);
return 0;
}
int main()
{
forward_list<int> a{ 1,2,3,4,5,6,7,8,9 };
print(a);
auto iter = a.begin();
auto pre = a.before_begin();
while (iter != a.end())//特别注意单链表版本插删函数的返回值
{
if (*iter % 2)
iter = a.erase_after(pre);
else
{
iter = a.insert_after(iter, *iter);
++iter;
++pre;//advance(pre,2)也可.
++pre;
}
}
print(a);
return 0;
}
练习9.32
这个题目实际是运算对象顺序不确定产生的未定义.
参考P.133,运算对象求值顺序是不确定的.
两种情况:iter = vi.insert(iter,*iter); 然后iter++;
这种情况下,(p316例子)vi最后一个元素是奇数9时会报错,最后一个是偶数(比如10)则不报错,但是结果与题意不符.
或者:(iter + 1) = vi.insert(iter,*iter);
这种情况下,必报错.无论最后一个元素是奇数还是偶数.因为尝试给超尾赋值.
注意:函数对于实参的求值顺序也是不确定的.但是本题传给insert()的是iter和*iter,而不是iter和*iter++,错误不在这里.
练习9.33
beg在插入元素后即失效,必须重新赋值.
练习9.34
如果vi空,则报错.
否则,如果第一个元素是偶数,则无限循环什么也不做.否则,插入新元素,如果新元素是偶数,则死循环什么也不做,否则,不停的插入奇数,直到遇到第一个偶数,死循环什么也不做.
是题目出错了还是我的书印错了??我觉得少了个花括号.
假设有花括号,如下:
iter = vi.begin();
while(iter != vi.end()){
if(*iter % 2)
iter = vi.insert(iter,*iter);
++iter;
}
如果当前数据data.
如果data是偶数,则iter又指向第一个奇数.
如果data是奇数,则iter指向这个奇数,判断下一个插入元素.
总之,这两种情况就是想考察,insert的返回值是指向所插入数据的第一个元素,迭代器应能越过新插入数值再+1.
练习9.35
capacity是当前的最大容量,size是当前元素的个数
练习9.36
capacity不可能小于size,否则size里多余的元素去哪里了呢.
可以理解成背包装苹果.
capacity是背包可以装苹果的总个数,
size是苹果的个数,
empty是背包里有没有苹果,
max_size是厂家生产的背包最最最厉害的那个可以装苹果的极限个数,
resize操作苹果的增加和减少,一般不扩充背包,当超过当前背包容量时就分配背包,
reserve告诉厂家背包最低限度应该装多少苹果,装的下就不必换背包,装不下才更换背包.
shrink_to_fit要求改小背包,使得背包恰好装满苹果.
练习9.37
array大小固定,list不连续,哪里有内存,哪里可以用,理论上capacity无上限.
练习9.38
1.5倍增长
练习9.39
首先给svec分配了1024个空间.
接下来填入用户输入word.如果后续填满就继续扩充(1024 * 1.5 )
接下来可能继续扩充空间,新空间的大小至少为1.5倍当前容量,也或许不扩充
练习9.40
256和512都还是1024
1000是1024 * 1.5(取决于编译器)
1048是1024 * 1.5 * 1.5
练习9.41
int main()
{
vector<char> tmp = { 'h','e','l','l','o',' ','w','o','r','l','d','\0' };
string word(tmp.begin(),tmp.end());
cout << word << endl;
return 0;
}
练习9.42
利用reserve(100);提前预留上100个空间.
练习9.43
void replace_str(string& s, const string& oldval, const string& newval)
{
auto p = s.begin();
int old_len = oldval.size();
int new_len = newval.size();
while (p + old_len <= s.end())
{
string tmp(p, p + old_len);
if (tmp == oldval)
{
p = s.erase(p, p + old_len);
p = s.insert(p, newval.begin(), newval.end());
p += new_len;
if (p == s.end())
return;
}
else
p++;
}
}
int main()
{
string s = "thothotho";
cout << s << endl;
replace_str(s, "tho", "through");
cout << s << endl;
return 0;
}
练习9.44
void replace_str(string& s, const string& oldval, const string& newval)
{
typedef string::size_type T;
T old_len = oldval.size();
T new_len = newval.size();
for (T i = 0; i < s.size(); ++i)
{
if (s.substr(i, old_len) == oldval)
{
s.replace(i, old_len, newval);
i += new_len - 1;
}
}
}
int main()
{
string s = "thothotho";
cout << s << endl;
replace_str(s, "tho", "through");
cout << s << endl;
return 0;
}
练习9.45
void adjust_str(string& name, const string& prev, const string& back)
{
name.insert(name.begin(), prev.begin(),prev.end());
name.append(back);
}
int main()
{
string s = "Jack";
adjust_str(s, "Mr.", "Jr.");
cout << s << endl;
return 0;
}
练习9.46
void adjust_str(string& name, const string& prev, const string& back)
{
name.insert(0, prev);
name.insert(name.size(), back);
}
int main()
{
string s = "Jack";
adjust_str(s, "Mr.", "Jr.");
cout << s << endl;
return 0;
}
练习9.47
int main()
{
string::size_type pos = 0;
string s1("ab2c3d7R4E6");
string numbers("0123456789");
while ((pos = s1.find_first_of(numbers, pos) ) != string::npos)
{
cout << s1[pos]<<" ";
++pos;
}
cout << endl;
pos = 0;
while ((pos = s1.find_first_not_of(numbers,pos) )!= string::npos)
{
cout << s1[pos] << " ";
++pos;
}
return 0;
}
练习9.48
string::npos
练习9.49
正确做法应该是写出来不在上下出头的,然后再做.
int main()
{
ifstream fin("word.txt");
if (!fin)
{
cout << "Cann't open file!\n";
return 0;
}
const string up_word("bdfhklt");
const string down_word("fgjpqy");
string word;
while (fin>>word)
{
string::size_type pos = 0, pre_pos = 0;
string::size_type max_len = 0;
string max_str;
pre_pos = word.find_first_not_of(up_word, 0);//寻找第一个不包含上出头的左侧端点
while ((pos = word.find_first_of(up_word, pre_pos)) != string::npos)//不包含上出头
{
string::size_type tmp = word.find_first_of(down_word, pre_pos );
if (tmp <= pos)
pos = tmp - 1;
string::size_type tmp_len = pos - pre_pos ;
if (tmp_len > max_len)//比较能否是当前最大
{
max_len = tmp_len;
max_str = word.substr(pre_pos, max_len);
}
pre_pos = word.find_first_not_of(up_word,pos + 1) ;//寻找下一个不包含上出头的左侧端点
if (pre_pos == string::npos)
break;
}
if (pos == string::npos)//以下有bug,本程序是错误的,考虑不周全
{
pos = word.size();
string::size_type tmp = word.find_first_of(down_word, pre_pos);
if (tmp <= pos)
pos = tmp - 1;
string::size_type tmp_len = pos - pre_pos;
if (tmp_len > max_len)//比较能否是当前最大
{
max_len = tmp_len;
max_str = word.substr(pre_pos, max_len);
}
}
cout << word<<"中最长的非上出头&非下出头字符串为: "<<max_str << endl;
}
fin.close();
return 0;
}
练习9.50
int main()
{
vector<string> data{"1234","2345","3456","4567"};
int sum = 0;
for (auto p = data.begin(); p != data.end(); ++p)
sum += stoi(*p);
cout << sum << endl;
double sum2 = 0;
vector<string> data2{ "1234.5","2345.6fdg7","0.3fdg456","gfh0.4567hj" };
string numbers("0123456789+-.");
for (auto p = data2.begin(); p != data2.end(); ++p)
sum2 += stod(p->substr(p->find_first_of(numbers)));
cout << sum2 << endl;
return 0;
}
练习9.51
头文件:
#pragma once
#include <iostream>
using std::string;
class Data
{
public:
typedef unsigned int UN;
public:
Data() = default;
Data(const string& data);
private:
UN m_year = 1900;
UN m_month = 1;
UN m_day = 1;
friend std::ostream& operator<<(std::ostream& os, const Data& data);
};
std::ostream& operator<<(std::ostream& os, const Data& data);
源代码:
#include "Data.h"
#include <vector>
#include <cctype>
#include <string>
Data::Data(const string& data)
{
typedef string::size_type Type;
std::vector<string> mon{ "January","February","March" };//意思意思就行
string split(" /,");//分隔符,只有空格和/和,
Type pos1 = data.find_first_of(split);
string month = data.substr(0,pos1 );//月份
Type pos2 = data.find_first_of(split, pos1 + 1);
string day = data.substr(pos1 + 1, pos2 - pos1 - 1 );//日
string year = data.substr(pos2 + 1);//年份
m_year = stoi(year);
m_day = stoi(day);
if (isdigit(month[0]))//用数字表示月份
m_month = stoi(month);
else//字母表示
{
for (auto p = mon.begin(); p != mon.end(); ++p)
{
if (p->find(month) != string::npos)
{
m_month = p - mon.begin() + 1;
break;
}
else//统统12月
{
m_month = 12;
break;
}
}
}
}
std::ostream& operator<<(std::ostream& os, const Data& data)
{
os << data.m_year << "年" << data.m_month << "月" << data.m_day << "日";
return os;
}
测试:
int main()
{
//Data d1;//默认
Data d2("January 1,1900");
Data d3("1/1/1900");
Data d4("Jan 1 1900");
cout << d2 << endl << d3 << endl << d4 << endl;
return 0;
}
有很多需要改进的地方,练练string的操作,有那么点意思就行.
练习9.52
有bug,找不到.
int calculate(int n1, char op, int n2)
{
switch (op)
{
case '+':
return n1 + n2;
case '-':
return n1 - n2;
case '*':
return n1 * n2;
case '/':
try {
return n1 / n2;
}
catch (exception)
{
cout << "除数不能为0\n";
}
}
}
int main()
{
stack<char> data;
const string expression = "(102+(5+2)*(4-1))";
auto p = expression.begin();
auto sum = 0;
while (p != expression.end())
{
if (*p == ')')//右括号
{
string num1, num2;
bool is_left = false;//是否是左侧操作数
char c;//临时变量
char op;//运算符
while (!data.empty() && (c = data.top()) != '(')//栈不空,同时栈顶非左括号
{
if (isdigit(c) && !is_left)//处理运算符右侧操作数
num2 += c;
else if (isdigit(c) && is_left)//处理左侧数字
num1 += c;
else//处理运算符
{
op = c;
is_left = true;
}
data.pop();//出栈
}
if (!data.empty())//左括号出栈
{
data.pop();
num1.reserve();//栈是FILO,所以翻转一下操作数
num2.reserve();
sum = calculate(stoi(num1), op, stoi(num2));
data.push(sum);
}
}
else //数字,运算符,左括号统统入栈
data.push(*p);
p++;
}
cout << "结果为: " << data.top()<< endl;
return 0;
}