C++ Primer习题解答 Chapter12

12-30

要实现的功能:

  1. 从文件读入文本,并保存以用于查找
  2. 给读入的文本建立一个从单词到其出现的全部行号的映射
  3. 读取用户输入的单词,查找该单词是否出现过,如果出现过打印出所在行和行号

根据上面列出来的基本需求,决定应该使用哪些数据结构:

  1. 首先我们需要一个容器来保存从文件中读取的文本,考虑到查找是以行为单位进行的,因此文本逐行保存,我们不妨用一个vector<string>来保存

  2. 因为要建立单词到行号的映射,所以肯定需要一个map,而行号又不能重复,所以宜采用set,最终推断其类型应该是map<string,set<vector<string>::size_type>>

  3. 为了更加规范,我们把一些操作和数据封装到相应的类中,一个TextQuery类用来执行文件读取,查询操作,另一个QueryResult类用来保存查询结果。

  4. 查询结果包含行号,和行的内容,这样我们就需要在QueryResult类中访问TextQuery类的数据,考虑到在本章中前面小节的实践经验,我们不难想到此处要求两个类共同维护一些相同的数据对象,使用动态内存分配创建对象,再用智能指针shared_ptr来管理是一个很好地选择。

  5. 鉴于以上考虑我们要使用这样几个类型:

    shared_ptr<vector<string>>

    shared_ptr<set<vector<string>::size_type>>

    map<string, shared_ptr<set<vector<string>::size_type>>>

基本的思路就是这样,下面就可以实现代码了:

#include<iostream>
#include<fstream>
#include<memory>
#include<vector>
#include<map>
#include<set>
#include<algorithm>
#include<string>
#include<sstream>

using namespace std;

class QueryResult;

class TextQuery
{
//内部数据成员
private:
	//文件文本
	shared_ptr <vector<string>> file;
	//行号
	shared_ptr<set<vector<string>::size_type>> lineNo;
	//映射
	map<string, shared_ptr<set<vector<string>::size_type>>> mapping;

//内部方法
private:


//对外提供接口
public:
	//构造
	TextQuery(ifstream &infile);
	QueryResult query(string word);

};

class QueryResult
{
private:
	//行号
	shared_ptr<set<vector<string>::size_type>> lineNo;
	//文件文本
	shared_ptr <vector<string>> file;
	string word;
public:
	QueryResult() = default;
	ostream& print();//打印查找结果
	QueryResult(shared_ptr<set<vector<string>::size_type>> s, 
		shared_ptr < vector<string>> v,	string word);
};

ostream& QueryResult::print()
{
	if (!lineNo) {
		cout << "nothing found!" << endl;
		return cout;
	}
	cout << word << " is found " << lineNo->size() << " times:" << endl;
	for (auto num : *lineNo) {
		cout << "(at line " << num << " )\t" << (*file)[num - 1] << endl;
	}
	return cout;
}

QueryResult::QueryResult(shared_ptr<set<vector<string>::size_type>> s,
	shared_ptr < vector<string>> v, string word) :file(v), lineNo(s),word(word) {}

//构造函数
TextQuery::TextQuery(ifstream &infile):file(new vector<string>)
{
	vector<string>::size_type number = 1;
	for (string line; getline(infile, line);++number) {
		file->push_back(line);//把当前行放入vector
		istringstream instring(line);
		for (string word; instring >> word;) {
			//下标访问map,如果键不存在会新建,值进行默认初始化(内置类型值初始化,类类型调用默认构造函数)
			auto &a = mapping[word]; //这里要用引用,否则赋值会引起引用计数增加
			if (!a) {
				a.reset(new set<vector<string>::size_type>({number}));
			}
			a->insert(number);
		}
	}
	
}

QueryResult TextQuery::query(string word)
{
	shared_ptr<set<vector<string>::size_type>> none;
	auto it = mapping.find(word);
	//如果找到了这个单词
	if (it != mapping.end()) {
		return(QueryResult(it->second, file, word));
	}
	else {
		return(QueryResult(none, file, word));
	}
}

//查找单词
void runQueries(ifstream& infile)
{
	TextQuery tq(infile);
	while (true) {
		std::cout << "enter word to look for, or q to quit: ";
		string word;
		if (cin>>word and word!="q") {
			//开始查询
			tq.query(word).print()<<endl;
		}
	}
}
int main(int argc, char*argv[])
{
	ifstream infile("../12-30/main.cpp");
	runQueries(infile);
	system("pause");
	return 0;
}

喔,浪费了好长时间

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值