C++Prime 第九章后22题

本文深入解析C++Prime第九章的习题,涵盖了list和forward_list的使用技巧,探讨了迭代器操作、内存管理和字符串处理等关键概念。通过具体代码示例,详细分析了各种数据结构的特点及应用,帮助读者掌握C++编程精髓。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值