C++学习笔记——C++ Primer Plus中文第六版 第十六章STL编程练习解答


发现答案资源不全,因此贴出自己的解答,都为STL应用基础题,如有谬误,还请不吝赐教。


第一题

要求:回文字符串判断(假定字符串中没有大小写、空格、标点符号等问题)

解答:

#include<iostream>
#include<string>
#include<ctype>
#include<algorithm>

int main(void) {
	using namespace std;
	string input;
	bool isPal(string);
	string tmp = "";
	cout << "Enter a string(empty string to quit):";
	while (getline(cin,input) && input.size() > 0) {
		if (isPal(tmp))
			cout << "It's a palindrome." << endl;
		else {
			cout << "It isn't a palindrome" << endl;
		}
		cout << "Enter a string(empty string to quit):";
	}
}

bool isPal(std::string s) {
	std::string r(s.rbegin(), s.rend());
	if (r == s)
		return true;
	else
		return false;
}

第二题

要求:第一题拓展,加上输入字符串中有大小写、空格和标点符号的情况,程序需要将这些忽略掉

解答:

#include<iostream>
#include<string>
#include<ctype>
#include<algorithm>

int main(void) {
	using namespace std;
	string input;
	bool isPal(string);
	string tmp = "";
	cout << "Enter a string(empty string to quit):";
	while (getline(cin,input) && input.size() > 0) {
		for (auto e : input) {
			if (isalpha(e))
				tmp.push_back(tolower(e));
		}
		

		if (isPal(tmp))
			cout << "It's a palindrome." << endl;
		else {
			cout << "It isn't a palindrome" << endl;
		}
		cout << "Enter a string(empty string to quit):";
	}
}

bool isPal(std::string s) {
	std::string r(s.rbegin(), s.rend());
	if (r == s)
		return true;
	else
		return false;
}

第三题

要求:从文件中读取单词,利用vector存储并输出到屏幕上,并打印个数

解答:

1.在.cpp文件目录下新建text文件“data.txt”,打开编辑并保存如下内容:

apiary beetle cereal danger ensign florid garage health insult jackal keeper loaner manage nonce onset
plaid quilt remote stolid train useful valid whence xenon yearn zippy

2.

#include<iostream>
#include<iterator>
#include<fstream>
#include<string>
#include<vector>

int main() {
	using namespace std;

	ifstream fin("data.txt");
	string input;
	vector<string>v1;

	while (fin >> input) {
		v1.push_back(input);
	}

	copy(v1.begin(), v1.end(), ostream_iterator<string, char>(cout, " "));//打印单词
	cout << endl << "共计" << v1.size() << "个单词";

	fin.close();

	cout << endl;
	system("pause");
	return 0;
}

第四题

要求:编写一个具有老式风格的接口函数,原型如下

              int reduce(long ar[], int n);

          实参应是数组名和数组元素个数,该函数对数组进行排序,删除重复值,返回缩减后数组中的元素数目。用STL函数编写。

解答:

#include<iostream>
#include<list>
#include<iterator>

int main() {
	using namespace std;

	int reduce(long[], int);

	long arr[] = { 1,4500,3120, 2791, 3200, 14, 560, 14, 3120, 3200, 3200, 3200 };//测试数组

	cout << "调用reduce前,数组元素依次如下" << endl;
	for (long e : arr) {
		cout << e << " ";
	}
	int count = sizeof(arr) / sizeof(long);
	cout << endl << "共有" << count << "个元素" << endl;
	
	count = reduce(arr, count);

	cout << "调用reduce后,数组元素依次如下" << endl;
	for (int i = 0; i < count; i++) {
		cout << arr[i] << " ";
	}
	cout << endl << "共有" << count << "个元素" << endl;

	cout << endl;
	system("pause");
	return 0;
}

int reduce(long arr[], int n) {
	std::list<long> myList;
	std::copy(arr, arr + n, std::back_insert_iterator<std::list<long>>(myList));
	myList.sort();
	myList.unique();
	int i = 0;
	for (long e : myList) {
		arr[i++] = e;
	}
	return myList.size();
}

第五题

要求:与第四题相同,但要编写的是模板函数,并用long实例和string实例测试

解答:

#include<iostream>
#include<list>
#include<iterator>
#include<string>

template<typename T>
void out(T arr[],int n);//因为long和string对象均可用cout打印,因此这里简化代码也用了模板

template <typename T>
int reduce(T arr[], int n);

using namespace std;

int main() {

	long arr[] = { 1,4500,3120, 2791, 3200, 14, 560, 14, 3120, 3200, 3200, 3200 };//测试数组
	string arr2[] = { "haha", "heihei", "hehe", "haha", "haha", "heihei" };

	out(arr,sizeof(arr)/sizeof(long));
	out(arr2, sizeof(arr2) / sizeof(string));


	cout << endl;
	system("pause");
	return 0;
}

template<typename T>
void out(T arr[],int n) {
	cout << "调用reduce前,数组元素依次如下" << endl;
	int count = n;
	for (int i = 0; i < count; i++) {
		cout << arr[i] << " ";
	}
	cout << endl << "共有" << count << "个元素" << endl;

	count = reduce(arr, count);


	cout << "调用reduce后,数组元素依次如下" << endl;
	for (int i = 0; i < count; i++) {
		cout << arr[i] << " ";
	}
	cout << endl << "共有" << count << "个元素" << endl;
}

template <typename T>
int reduce(T arr[], int n) {
	std::list<T> myList;
	std::copy(arr, arr + n, std::back_insert_iterator<std::list<T>>(myList));
	myList.sort();
	myList.unique();
	int i = 0;
	for (T e : myList) {
		arr[i++] = e;
	}
	return myList.size();
}

第六题

要求:用STL模板类queue实现ATM模拟,允许用户输入三个数:队列的最大长度、程序模拟的持续时间(单位为小时)和平均每小时的客户数。程序使用循环,每次循环代表一分钟。在每分钟的循环中,程序将完成下面的工作:

  1.        判断是否来了新客户。如果来了,且此时队列未满,则将它添加到队列中,否则拒绝客户入队;
  2.        如果没有客户在进行交易,则选取队列的第一个客户。确定该客户的已等候时间,并将waitTime计数器设置为新客户所需的处理时间。
  3.        如果客户正在处理中, 则将waitTime计数器减1.
  4.        记录各种数据,如获得服务的客户数目、被拒绝的客户数目、排队等候的累积时间以及累积的队列长度等。

     当模拟循环结束时, 程序将报告各种统计结果。

解答:

为了更多地利用STL,并完成一个稍完整的ATM小系统,这里把本题复杂化,写得比较多

//---ATM.h
#pragma once
#include<ctime>
#include<queue>
#include<vector>
using namespace std;

//尽管这里其实没必要数据封装以及继承,但为了迎合OOP思想,还是写个类吧

class ATM {
private:
	int maxLength;
	time_t startTime;
	double duration;
	int averageClientNum;
	queue<time_t> line;
	vector<time_t> comeTime;
	int currentLeftTime = 0;
	double totalWaitingTime = 0;
	int totalLineLength = 0;
	int currentClientNum = 0;
	int rejectClientNum = 0;

	void circle();

	void createComeTime();
	bool isCome();
	bool isFull();
	void enter();
	void reject();

	void deal();
	int getDealTime();

	time_t getWaitingTime(time_t before);

	int getCurrentClientNum();
	int getRejectClientNum();
	double getTotalWaitingTime();
	int getTotalLineLength();

	void over();
	

public:
	ATM(int maxL = 3, double dur = 24, int aver = 40) :maxLength(maxL), duration(dur), averageClientNum(aver) {};
	void work();
	
};

//--ATP.cpp
#include "ATM.h"
#include<iostream>
#include<ctime>
#include<queue>
#include<vector>
#include<Windows.h>

using namespace std;

#define MAXDEALTIME 5

void ATM::over()
{
	cout << "------------------" << endl;
	cout << "当前统计结果如下" << endl;
	cout << "------------------" << endl;
	cout << "获得服务的客户数目:" << getCurrentClientNum() << endl;
	cout << "被拒绝的的客户数目:" << getRejectClientNum() << endl;
	cout << "排队等候的累积时间:" << getTotalWaitingTime() << endl;
	cout << "累积的队列长度:" << getTotalLineLength() << endl;
}

void ATM::work()
{
	//这方便测试,假设一小时是一分钟;一分钟是一秒;
	startTime = time(0);
	double minutes = 60 * duration;
	createComeTime();
	cout << "ATM开始运行" << endl;
	while (static_cast<double>(time(0) - startTime) <= minutes) {
		Sleep(1000);
		circle();
	}
	cout << "时间到,ATM运行结束" << endl;
}

void ATM::circle()
{
	cout << "---------------------------------------------------------------------" << endl;
	if (isCome()) {
		if (isFull()) {
			cout << "当前队列已满" << endl;
			reject();
		}
		else {
			enter();
			if (currentLeftTime == 0) {
				deal();
				currentLeftTime = getDealTime();
			}
		}
	}
	else {
		cout << "没有客户前来" << endl;
	}
	if (currentLeftTime > 0) {
		currentLeftTime--;
		cout << "当前客户交易剩余时间为" << currentLeftTime << endl;
		if(currentLeftTime == 0)
			cout << "当前客户交易结束" << endl;
	}
	over();
	cout << "本轮循环结束" << endl;
	cout << "---------------------------------------------------------------------" << endl;
}

void ATM::createComeTime()
{
	srand(time(NULL));
	int totalClientNum = duration * averageClientNum;
	time_t cometime;
	for (int i = 0; i < totalClientNum; i++) {
		cometime = (rand() % static_cast<long>(60 * duration-1)) + startTime+1;
		comeTime.push_back(cometime);
	}
	sort(comeTime.begin(), comeTime.end());
}

bool ATM::isCome()
{
	time_t currentTime = time(NULL);
	if (comeTime.size() > 0 && comeTime.front() <= currentTime)
		return true;
	return false;
}

bool ATM::isFull()
{
	if (line.size() >= maxLength)
		return true;
	return false;
}

void ATM::enter()
{

		line.push(comeTime.front());
		double waitingTime =static_cast<double>(getWaitingTime(comeTime.front()));
		totalWaitingTime += waitingTime;
		cout << "新客户已入队,他已等候时间为" << waitingTime << endl;
		totalLineLength++;

}

void ATM::reject()
{
	cout << "入队请求被拒" << endl;
	comeTime.erase(comeTime.begin());
	rejectClientNum++;
}

void ATM::deal()
{
	totalWaitingTime += static_cast<double>(time(NULL) - line.front());
	line.pop();
	cout << "当前客户交易开始" << endl;
	comeTime.erase(comeTime.begin());
	currentClientNum++;
}

int ATM::getDealTime()
{
	return rand() % MAXDEALTIME+1;
}

time_t ATM::getWaitingTime(time_t before)
{
	return time(NULL) - before;
}

int ATM::getCurrentClientNum()
{
	return currentClientNum;
}

int ATM::getRejectClientNum()
{
	return rejectClientNum;
}

double ATM::getTotalWaitingTime()
{
	return totalWaitingTime;
}

int ATM::getTotalLineLength()
{
	return totalLineLength;
}
//--main.cpp
#include"ATM.h"


int main(void) {
	using namespace std;

	int maxLength, averageClientNum;
	double duration;

	cout << "请输入队列最大长度:";
	cin >> maxLength;
	cout << "请输入程序模拟的持续时间(单位为小时):";
	cin >> duration;
	cout << "请输入平均每小时的客户数:";
	cin >> averageClientNum;
	ATM atm1(maxLength, duration, averageClientNum);
	atm1.work();

	cout << endl;
	system("pause");
	return 0;
}

第七题

   使用了random_shuffle,用法陈旧因此弃掉

第八题

题目:

     Mat和Pat希望邀请他们的朋友来参加派对。他们分别输入自己的朋友姓名列表,然后将两人的朋友姓名列表合并,得到不重复的被邀请者名单。

解答:

分析后可知,采用STLset容器极其相关算法最为简单,也就是求并集的过程,但注意set_union同copy一样,最后的一个参数要求输出迭代器且被输出容器容量足够,不能用C.begin(),因此采用insert_iterator构造输出迭代器

#include<iostream>
#include<iterator>
#include<set>
#include<vector>
#include<algorithm>
#include<string>

int main(void) {
	using namespace std;

	void input(string, set<string>&);
	
	set<string>nameList1, nameList2, nameList3;
	
	input("Mat", nameList1);
	input("Pat", nameList2);
	set_union(nameList1.begin(), nameList1.end(), nameList2.begin(), nameList2.end(), insert_iterator<set<string>>(nameList3, nameList3.begin()));
	cout << "最终得出的邀请名单如下:" << endl;
	for (string e : nameList3) {
		cout << e << endl;
	}

	cout << endl;
	system("pause");
	return 0;
}

void input(std::string name, std::set<std::string>& s) {
	std::cout << "请输入" << name << "的朋友名单(以空格分隔,回车结束):";
	std::string tmp;
	std::vector<std::string> v;
	while (std::cin >> tmp) {
		v.push_back(tmp);
		if (std::cin.get() == '\n')
			break;
	}
	std::copy(v.begin(), v.end(), std::insert_iterator<std::set<std::string>>(s,s.begin()));
}

第九题

要求:利用ctime中的clock()和STL完成下列目的

  1.  创建大型vector<int>对象vi0, 并使用rand()给它赋初值;
  2.  创建vector<int>对象vi和list<int>对象li, 它们的长度和初始值与vi0相同;
  3.  计算使用STL算法sort()对vi进行排序所需的时间,再计算使用list的方法sor()对li进行排序所需的时间。
  4. 将li重置为排序的vi0内容,并计算执行如下操作所需的时间:将li的内容复制到vi中,对vi进行排序,并将结果复制到li中。

解答:

#include<iostream>
#include<vector>
#include<algorithm>
#include<ctime>
#include<random>
#include<list>
#include<iterator>

using namespace std;

clock_t getTime(list<int>&li);
clock_t getTime(vector<int>&vi);
clock_t getTime(list<int>&li, vector<int>&vi);
void copy2(list<int>& li, vector<int>&vi);

int main(void) {

	int getRandom(int e);
	vector<int>vi0(1000);
	vector<int>vi;
	list<int>li;
	random_device dev;
	uniform_int_distribution<int> dist(-100, 100);

	for (auto &e : vi0) {
		e = dist(dev);
	}
	copy(vi0.begin(), vi0.end(), insert_iterator<vector<int>>(vi, vi.begin()));
	copy(vi0.begin(), vi0.end(), insert_iterator<list<int>>(li, li.begin()));
	cout << "初始化完成" << endl;

	cout << "使用sort()对vi进行排序所需的时间为:" << getTime(vi) << endl;
	cout << "使用li.sort()对li进行排序所需的时间为:" << getTime(li) << endl;
	cout << "先将li拷贝到vi在对vi使用STL sort()排序后再拷贝会li所需的时间为:" << getTime(li,vi) << endl;

	cout << endl;
	system("pause");
	return 0;
}


clock_t getTime(list<int>&li) {
	clock_t start = clock();
	li.sort();
	return clock() - start;
}

clock_t getTime(vector<int>&vi) {
	clock_t start = clock();
	sort(vi.begin(),vi.end());
	return clock() - start;
}


clock_t getTime(list<int>&li, vector<int>&vi){
		clock_t start = clock();
		copy2(li, vi);
		return clock() - start;
}



void copy2(list<int> &li, vector<int> &vi) {
	vi.clear();
	for (int e : li) {
		vi.push_back(e);
	}
	sort(vi.begin(), vi.end());
	li.clear();
	for (int e : vi) {
		li.push_back(e);
	}
}

第十题

原题没意思,这里我加以改编题目拓展了一下。

要求:实现一个书单相关功能,使其能够实现如下功能(使用vector<shared_ptr<Review>>存储书籍信息)

  1. 按原始顺序显示
  2. 按字母表顺序显示
  3. 按评级升序显示
  4. 按评级降序显示
  5. 按价格升序显示
  6. 按价格降序显示
  7. 退出

假设书单内容为如下:

  1.   Harry Potter and the Goblet of Fire    9     ¥68.5
  2.   To Kill a Mockingbird      7     ¥78
  3.   Pride and Prejudice        8     ¥70.50
  4.   Fifty Shades of Grey     5  ¥71
  5.   Great Expectations     7   ¥ 45

解答:

#include<iostream>
#include<vector>
#include<memory>
#include<string>
#include<algorithm>
#include<iterator>

using namespace std;
typedef struct Review {
	string name;
	int rate;
	double price;
}Review;

class BookList {
private:
	vector<shared_ptr<Review>> books;

	static bool cmpByAlpha(shared_ptr<Review> first, shared_ptr<Review> second);
	static bool cmpByRate(shared_ptr<Review> first, shared_ptr<Review> second);
	static bool cmpByPrice(shared_ptr<Review> first, shared_ptr<Review> second);
	void out(vector<shared_ptr<Review>> b = {});
public:
	BookList(vector<shared_ptr<Review>> &arr);
	void outByInit();
	void outByAlpha(bool sequence = true);
	void outByRate(bool sequence = true);
	void outByPrice(bool sequence = true);
};

bool BookList::cmpByAlpha(shared_ptr<Review> first, shared_ptr<Review> second)
{
	if(first->name >= second->name)
		return false;
	return true;
}

bool BookList::cmpByRate(shared_ptr<Review> first, shared_ptr<Review> second)
{
	if (first->rate >= second->rate)
		return false;
	else
		return true;
}

bool BookList::cmpByPrice(shared_ptr<Review> first, shared_ptr<Review> second)
{
	if (first->price >= second->price)
		return false;
	else
		return true;
}

void BookList::out(vector<shared_ptr<Review>> b)
{
	if (b.size() == 0)
		b = books;
	for (auto e : b) {
		cout << "-----------------------------" << endl;
		cout << "name: " << e->name << endl;
		cout << "rate: " << e->rate << endl;
		cout << "price: ¥" << e->price << endl;
		cout << "-----------------------------" << endl << endl;
	}
}

BookList::BookList(vector<shared_ptr<Review>> &arr)
{
	for (auto e : arr) {
		books.push_back(e);
	}
}

void BookList::outByInit()
{
	cout << "按原序输出如下" << endl;
	out();
}

void BookList::outByAlpha(bool sequence)
{
	
	vector<shared_ptr<Review>> books2;
	copy(books.begin(), books.end(), insert_iterator<vector<shared_ptr<Review>>>(books2, books2.begin()));
	if (sequence) {
		cout << "按字母升序输出如下" << endl;
		sort(books2.begin(), books2.end(), BookList::cmpByAlpha);
	}
	else {
		cout << "按字母降序输出如下" << endl;
		sort(books2.rbegin(), books2.rend(), BookList::cmpByAlpha);
	}
	out(books2);
}

void BookList::outByRate(bool sequence)
{
	vector<shared_ptr<Review>> books2;
	copy(books.begin(), books.end(), insert_iterator<vector<shared_ptr<Review>>>(books2, books2.begin()));
	if (sequence) {
		cout << "按评级升序输出如下" << endl;
		sort(books2.begin(), books2.end(), BookList::cmpByRate);
	}
	else {
		cout << "按评级降序输出如下" << endl;
		sort(books2.rbegin(), books2.rend(), BookList::cmpByRate);
	}
	out(books2);
}

void BookList::outByPrice(bool sequence)
{
	vector<shared_ptr<Review>> books2;
	copy(books.begin(), books.end(), insert_iterator<vector<shared_ptr<Review>>>(books2, books2.begin()));
	if (sequence) {
		cout << "按价格升序输出如下" << endl;
		sort(books2.begin(), books2.end(), cmpByPrice);
	}
	else {
		cout << "按价格降序输出如下" << endl;
		sort(books2.rbegin(), books2.rend(), cmpByPrice);
	}
	out(books2);
}


int main(void) {

	int showMenu();

	vector<shared_ptr<Review>> arr = { 
		shared_ptr<Review>(new Review{"Harry Potter and the Goblet of Fire",9,68.5}),
		shared_ptr<Review>(new Review{"To Kill a Mockingbird", 7, 70.50}),
		shared_ptr<Review>(new Review{"Pride and Prejudice", 8, 70.50}),
		shared_ptr<Review>(new Review{" Fifty Shades of Grey", 5, 71.0}),
		shared_ptr<Review>(new Review{"Great Expectations", 7, 45.0}),
	};
	BookList list1(arr);

	int option;
	while ((option = showMenu()) != 0) {
		switch (option)
		{
		default:
			continue; break;
		case 1:
			list1.outByInit(); break;
		case 2:
			list1.outByAlpha(); break;
		case 3:
			list1.outByAlpha(false); break;
		case 4:
			list1.outByRate(); break;
		case 5:
			list1.outByRate(false); break;
		case 6:
			list1.outByPrice(); break;
		case 7:
			list1.outByPrice(false); break;
		}
		system("pause");
		system("cls");
	}

	cout << endl;
	system("pause");
	return 0;
}

int showMenu() {
	cout << "本程序是一个书单打印程序,请输入整数0-7选择打印方式" << endl;
	cout << "1.按原序打印;" << endl;
	cout << "2.按字母升序打印;" << endl;
	cout << "3.按字母降序打印;" << endl;
	cout << "4.按评级升序打印;" << endl;
	cout << "5.按评级降序打印;" << endl;
	cout << "6.按价格升序打印;" << endl;
	cout << "7.按价格降序打印;" << endl;
	cout << "0.退出;" << endl;
	int input;
	cin >> input;
	return input;
}

这里尤其注意一个点,自定义的谓词函数不能是稳定的,因为sort()非稳定算法。所以应是当">="时返回顺序错误(false),而写“>”会报错。 

猜你喜欢

转载自blog.csdn.net/weixin_40861847/article/details/83030150
今日推荐