一、设计思路

数据结构:

1、读取文件时,要记住文件的每一行,并且要将每一行分解为独立的单词

vector<string> vec; 
istringstream

2、输出时提供每个单词与其关联的行号,且用map将单词与行号关联

map<string, set<int>> m_dit;

类的设计

1、设计保存输入文件的类TextQuery,设计QueryResult来保存查询结果。

TextQuery类中的query将返回这个结果

class TextQuery{
public:
    vector<string> file;
    map<stirng, set<int>> wm;
    QueryResult query(cosnt string &ought) const;
};

2、类之间共享数据,QueryResult要表达的查询结果,数据保存在TextQuery对象中,返回指向

TextQuery对象内部的迭代器,可以避免拷贝操作,使用shared_ptr反映共享关系

shared_ptr<vector<string>> m_file;
map<string, shared_ptr<set<int>>> wm;

3、QueryResult类

class QueryResult{
    string sought;        //单词
    shared_ptr<set<int>> lines;    //行号
    shared_ptr<vector<string>> file; //输入文件
};

 一些难点

1、TextQuery构造函数

class TextQuery{
    TestQuery(ifstream &ifs):file(new vector<string>()){    //构造    
    //vector<string>为智能指针,所以要new
        ....
        while(iss >> word){
            //单词不在wm中,以word为下标添加一项
            auto &lines = wm[word];        //返回一个shared_ptr指针
            if(!lines)    lines.reset(new set<int>()); //指针为空,新建一个set放行号
            lines->insertt(n);    //不管是否为空指针,都将行号添加到set中
        }
    }
};

TextQuery构造完成后,结果便存到了数据结构中,之后创建TextQuery对象tq,执行query函数

2、query函数

接受一个string参数,找到后,构造一个QueryResult保存string、m_file以及从wm中提取的set

string未找到:定义一个static对象,指向空set的shared_ptr,返回此对象的一个拷贝

QueryResult query(const string &sought) const{
    //未找到,返回一个指向该set的指针
    static shard_ptr<set<<int>> nodata(new set<int>());
    auto loc = find(sought); //不用下标运算符,避免插入
    if(loc == wm.end()){
        return QueryResult(sought, nodeta, file);
    }else{
        return QueryResult(sought, loc->second, file);
    }
}

3、QueryResult重载<<

os << rhs.sought << " occurs " << rhs.lines->size() << " "
   << ((rhs.lines->size() > 1) ? "times" : "time") << endl;
//set的size成员说明单词出现多少次

for(auto num  : *rhs.lines){
    os << "\t(line " << num + 1 << ")"    //避免行号从0开始给用户的困惑
       << *(rhs.file()->begin() + num) << endl;
}

单词未找到情况:set为空,第一条输出语句输出单词出现0次,*rhs.lines为空,for一次也不执行

 源代码:
  1 #include <iostream>
  2 #include<vector>
  3 #include<string>
  4 #include<map>
  5 #include<memory>
  6 #include<set>
  7 #include<fstream>
  8 #include<sstream>
  9 
 10 using std::istringstream;
 11 using std::ifstream;
 12 using std::ofstream;
 13 using std::vector;
 14 using std::string;
 15 using std::map;
 16 using std::shared_ptr;
 17 using std::set;
 18 using std::cin;
 19 using std::cout;
 20 using std::endl;
 21 
 22 /*借助智能指针实现文本查询程序*/
 23 
 24 class QueryResult{
 25 public:
 26     QueryResult(string s, shared_ptr<set<int>> p, shared_ptr<vector<string>> f):sought(s), lines(p), file(f){
 27 
 28     }
 29 
 30     friend std::ostream &operator<<(std::ostream &os, const QueryResult &rhs);
 31 private:
 32     string sought;
 33     shared_ptr<set<int>> lines;
 34     shared_ptr<vector<string>> file;
 35 };
 36 
 37 
 38 std::ostream &operator<<(std::ostream &os, const QueryResult &rhs){
 39     os << rhs.sought << " occurs " << rhs.lines->size() << " "
 40        << ((rhs.lines->size() > 1) ? "times" : "time") << endl;
 41     
 42     for(auto num : *rhs.lines){ //遍历set中的行号,通过行号打印vector中的内容
 43         os << "\t(line )" << num + 1 << ")"
 44            << *(rhs.file->begin() + num) << endl;
 45     }
 46 
 47     return os;
 48 }
 49 
 50 //读取文件,存到数据结构中
 51 class TextQuery{
 52 public:
 53     TextQuery(ifstream &ifs);
 54 
 55     QueryResult query(const string &ought) const; //查询,查询得到的结果返回给QueryResult
 56 
 57     shared_ptr<vector<string>> m_file;
 58     map<string, shared_ptr<set<int>>> m_dict;
 59 };
 60 
 61 TextQuery::TextQuery(ifstream &ifs):m_file(new vector<string>){
 62     string line;
 63     while(getline(ifs, line)){
 64         int n = m_file->size() - 1;//当前行号
 65         m_file->push_back(line);
 66 
 67         string word;
 68         istringstream iss(line);
 69         while(iss >> word){
 70            auto &relationship =  m_dict[word];  //单词与行号之间的关系,返回的是一个shared_ptr
 71            if(!relationship)    relationship.reset(new set<int>()); //指针为空,新建一个set存放行号
 72            relationship->insert(n); //指针不为空,说明记录该单词次数的set存在,将行号存起来
 73         }
 74     }
 75 }
 76 
 77 QueryResult TextQuery::query(const string &ought) const{    //打印结果
 78    
 79     auto loc = m_dict.find(ought);  //寻找该单词
 80     shared_ptr<set<int>> nodata(new set<int>());
 81 
 82     if(loc != m_dict.end()){
 83         return QueryResult(ought, loc->second, m_file);     //用QueryResult类存放结果
 84     }else{
 85         return QueryResult(ought, nodata, m_file);
 86     }
 87     
 88 }
 89 
 90 void runQueries(ifstream &ifs){
 91     TextQuery tq(ifs);
 92 
 93     while(1){
 94         cout << "enter word to look for, or q to quit:";
 95 
 96         string s;
 97         if(!(cin >> s) || s == "q"){
 98             break;
 99         }
100         cout << tq.query(s) << endl;
101     }
102 
103 }
104 
105 int main(int argc, char **argv)
106 {
107     ifstream ifs("china_daily.txt");
108     runQueries(ifs);
109 
110     return 0;
111 }