《C++ Primer》第12章 12.3节习题答案

《C++ Primer》第12章 动态内存

12.3节使用标准库:文本查询程序 习题答案

练习12.27:TextQuery和QueryResult类只使用了我们已经介绍过的语言和标准库特性。不要提前看后续章节内容,只用已经学到的知识对这两个类编写你自己的版本。

【出题思路】

本题综合练习已学过的知识实现文本查询程序。

【解答】

#ifndef PROGRAM12_27_H
#define PROGRAM12_27_H

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

using std::shared_ptr;
using std::vector;
using std::string;
using std::ifstream;

class QueryResult;
class TextQuery
{
public:
    using LineNo = vector<string>::size_type;

    TextQuery(ifstream &);
    QueryResult query(const string &) const;

private:
    shared_ptr<vector<string>> input;
    std::map<string, shared_ptr<std::set<LineNo>>> result;
};

class QueryResult
{
public:
    friend std::ostream& print(std::ostream&, const QueryResult&);

public:
    QueryResult(const string& s, shared_ptr<std::set<TextQuery::LineNo>> set, shared_ptr<vector<string>> v)
    :word(s), nos(set), input(v)
    {

    }

private:
    string word;
    shared_ptr<std::set<TextQuery::LineNo>> nos;
    shared_ptr<vector<string>> input;
};

TextQuery::TextQuery(std::ifstream& ifs):input(new vector<string>)
{
    LineNo lineNo{0};
    for(string line; std::getline(ifs, line); ++lineNo)
    {
        input->push_back(line);
        std::istringstream line_stream(line);
        for(string text, word; line_stream >> text; word.clear())
        {
            //避免读一个单词后跟标点符号(如:word,)
            std::remove_copy_if(text.begin(), text.end(), std::back_inserter(word), ispunct);
            //use reference avoid count of shared_ptr add.
            auto &nos = result[word];
            if(!nos) nos.reset(new std::set<LineNo>);
            nos->insert(lineNo);
        }
    }
}


QueryResult TextQuery::query(const string& str) const
{
    //使用静态只分配一次。
    static shared_ptr<std::set<LineNo>> nodate(new std::set<LineNo>);
    auto found = result.find(str);
    if(found == result.end())
    {
        return QueryResult(str, nodate, input);
    }
    else
    {
        return QueryResult(str, found->second, input);
    }
}

std::ostream& print(std::ostream& out, const QueryResult& qr)
{
    out << qr.word << "  occurs  " << qr.nos->size()
    << (qr.nos->size() > 1? " times" : " time") << std::endl;
    for(auto i : *qr.nos)
    {
        out << "\t(line " << i + 1 << ") " << qr.input->at(i) << std::endl;
    }
    return out;
}

#endif // PROGRAM12_27_H
#include <iostream>
#include "program12_27.h"

using std::cout;
using std::endl;

void runQueries(std::ifstream& infile)
{
    TextQuery tq(infile);
    while(true)
    {
        std::cout << "enter word to lock for, or q to quit:" << endl;
        string s;
        if(!(std::cin >> s) || (s == "q"))
            break;
        print(std::cout, tq.query(s)) << std::endl;
    }
}


int main(int argc, const char* argv[])
{
    std::ifstream in(argv[1]);
    if(!in)
    {
        cout << "无法打开输入文件" << endl;
        return -1;
    }
    runQueries(in);

    return 0;
}

data12_27.txt文件内容为:

Alice Emma has long flowing red hair.
Her Daddy says when the wind blows
through her hair, it looks almost alive,
like a fiery bird in flight.
A beautiful fiery bird, he tells her,
magical but untamed.
"Daddy, shush, there is no such thing,"
she tells him, at the same time wanting
him to tell her more.
Shyly, she asks, "I mean, Daddy, is there?"

设置命令行参数:

《C++ Primer》第12章 12.3节习题答案

 运行结果:

《C++ Primer》第12章 12.3节习题答案《C++ Primer》第12章 12.3节习题答案

 练习12.28:编写程序实现文本查询,不要定义类来管理数据。你的程序应该接受一个文件,并与用户交互来查询单词。使用vector、map和set容器保存来自文件的数据并生成查询结果。

【出题思路】

采用过程式程序设计而非面向对象的程序设计来解决这个问题,并体会两者的差异。

【解答】

总体设计思路与面向对象的版本相似,但有一些差异:

1.由于不用类来管理数据,file和wm都定义为全局变量,便于在函数间共享。当然也可以定义为局部变量,通过函数参数传递。

2.由于不必进行不同类对象间的数据共享,因此file和wm中的set都不必用shared_ptr管理,直接定义为vector和set即可。使用它们的代码也要相应修改。

3.由于不用类来保存查询结果,因此将query和print函数合二为一。

 

上一篇:HBASE学习


下一篇:JVM:26 案例:百万级用户的在线教育平台,如何基于G1垃圾回收器优化性能?