15_41習題答案

#include <iostream>
#include <vector>
#include <fstream>
#include <sstream>
#include <string>
#include <set>
#include <map>
#include <stdexcept>
#include <iterator>
#include <algorithm>
#include <numeric>

using namespace::std;

class TextQuery {
    public:
        typedef std::vector<std::string>::size_type line_no;
        void read_file(std::ifstream &is)
            {store_file(is); build_map();}
        std::set<line_no> run_query(const std::string&) const;
        std::string text_line(line_no) const;
        line_no size() const { return lines_of_text.size(); }
    private:
        void store_file(std::ifstream &is);
        void build_map();
        std::vector<std::string> lines_of_text;
        std::map< std::string, std::set<line_no> > word_map;
};

void TextQuery::store_file(std::ifstream &is)
{
    is.clear();
    string line;
    while(getline(is, line))
    {
        lines_of_text.push_back(line);
    }
    is.close();
    is.clear();
}

void TextQuery::build_map()
{
    string s;
    for(TextQuery::line_no num = 1; num < lines_of_text.size(); ++num)
    {
        istringstream iss(lines_of_text[num]);
        while(iss >> s)
        {
            word_map[s].insert(num);
        }
    }
}

std::string TextQuery::text_line(TextQuery::line_no ln) const 
{
    if(ln < lines_of_text.size()) 
    {
        return lines_of_text[ln];
    }
    throw std::out_of_range("line number out of range");
}

std::set<TextQuery::line_no> TextQuery::run_query(const std::string&  word) const 
{
    std::map<std::string, std::set<TextQuery::line_no> >::const_iterator iter = word_map.find(word);
    if(iter != word_map.end())
    {
        return iter->second;
    }
    else
    {
        return std::set<TextQuery::line_no>();
    }
}


class Query_base {
    friend class Query;
protected:
    typedef TextQuery::line_no line_no;
    virtual ~Query_base() {}
private:
    virtual set<line_no>
        eval(const TextQuery&) const = 0;
    virtual ostream& display(ostream& = cout) const = 0;
};

class Query {
    friend Query operator~(const Query&);
    friend Query operator|(const Query &, const Query &);
    friend Query operator&(const Query &, const Query &);
public:
    Query(const string&);
    Query(const Query &c);
    ~Query() { decr_use(); }
    Query& operator=(const Query&);
    set<TextQuery::line_no>
        eval(const TextQuery &t) const { return q->eval(t); }
    ostream &display(ostream &os) const
        { return q->display(os); }
private:
    Query(Query_base *query): q(query), use(new size_t(1)) { }
    Query_base *q;
    size_t *use;
    void decr_use()
    { if (--*use == 0) { delete q; delete use; } }
};

inline ostream& operator<<(ostream& os, const Query &q)
{
    return q.display(os);
}

class WordQuery : public Query_base {
    friend class Query;
    WordQuery(const string &s): query_word(s) { }
    set<line_no> eval(const TextQuery &t) const
        { return t.run_query(query_word); }
    ostream& display(ostream &os) const
        { return os << query_word; }
    string query_word;
};

inline Query::Query(const string& s): q(new WordQuery(s)), use(new size_t(1)) { }
inline Query::Query(const Query &c): q(c.q), use(c.use){ ++*use; }
inline Query& Query::operator=(const Query &c)
{
    ++*c.use;
    decr_use();
    this->q = c.q;
    this->use = c.use;
    return *this;
}

class NotQuery: public Query_base {
    friend Query operator~(const Query &);
    NotQuery(Query q): query(q) { }
    set<line_no> eval(const TextQuery&) const;
    ostream& display(ostream &os) const
        { return os << "~(" << query << ")"; }
    const Query query;
};

class BinaryQuery: public Query_base {
protected:
    BinaryQuery(Query left, Query right, string op):
        lhs(left), rhs(right), oper(op) { }
    ostream& display(ostream &os) const 
        { return os << "(" << lhs << " " << oper << " "
                << rhs << ")"; }
    const Query lhs, rhs;
    const string oper;
};

class AndQuery: public BinaryQuery {
    friend Query operator&(const Query&, const Query&);
    AndQuery(Query left, Query right):
        BinaryQuery(left, right, "&") { }
    set<line_no> eval(const TextQuery&) const;
};

class OrQuery: public BinaryQuery {
    friend Query operator|(const Query&, const Query&);
    OrQuery(Query left, Query right):
        BinaryQuery(left, right, "|") { }
    set<line_no> eval(const TextQuery&) const;
};

set<TextQuery::line_no>
OrQuery::eval(const TextQuery& file) const
{
    set<line_no> right = rhs.eval(file), left = lhs.eval(file);

    /*
    std::set<TextQuery::line_no>::iterator iter = left.begin();
    cout << "left element occurs " << left.size() << " times" << endl;
    while(iter != left.end())
    {
        cout << "\t(line " << *iter << "):\t" << file.text_line(*iter) << endl;  
        ++iter;
    }

    iter = right.begin();
    cout << "right element occurs " << right.size() << " times" << endl;
    while(iter != right.end())
    {
        cout << "\t(line " << *iter << "):\t" << file.text_line(*iter) << endl;  
        ++iter;
    }
    */
    left.insert(right.begin(), right.end());
    return left;
}

set<TextQuery::line_no>
AndQuery::eval(const TextQuery& file) const
{
    set<line_no> left = lhs.eval(file), right = rhs.eval(file);
    set<line_no> ret_lines;
   
    /*
    std::set<TextQuery::line_no>::iterator iter = left.begin();
    cout << "left element occurs " << left.size() << " times" << endl;
    while(iter != left.end())
    {
        cout << "\t(line " << *iter << "):\t" << file.text_line(*iter) << endl;  
        ++iter;
    }

    iter = right.begin();
    cout << "right element occurs " << right.size() << " times" << endl;
    while(iter != right.end())
    {
        cout << "\t(line " << *iter << "):\t" << file.text_line(*iter) << endl;  
        ++iter;
    }
    */

    set_intersection(left.begin(), left.end(), 
            right.begin(), right.end(),
            inserter(ret_lines, ret_lines.begin()));
    return ret_lines;
}

set<TextQuery::line_no>
NotQuery::eval(const TextQuery& file) const
{
    set<TextQuery::line_no> has_val = query.eval(file);
    set<line_no> ret_lines;
    for(TextQuery::line_no n = 0; n != file.size(); ++n)
    {
        if(has_val.find(n) == has_val.end())
            ret_lines.insert(n);
        return ret_lines;
    }
}

inline Query operator&(const Query &lhs, const Query &rhs)
{
    return new AndQuery(lhs, rhs);
}

inline Query operator|(const Query &lhs, const Query &rhs)
{
    return new OrQuery(lhs, rhs);
}

inline Query operator~(const Query &oper)
{
    return new NotQuery(oper);
}

int main(void)
{
    Query q = Query("class") & Query("Query") | Query("inline");
    TextQuery tq;
    ifstream ifs(__FILE__);
    tq.read_file(ifs);
    cout << q << endl;
    set<TextQuery::line_no> rs = q.eval(tq);
    std::set<TextQuery::line_no>::iterator iter = rs.begin();
    cout << "element occurs " << rs.size() << " times" << endl;
    while(iter != rs.end())
    {
        cout << "\t(line " << *iter << "):\t" << tq.text_line(*iter) << endl;  
        ++iter;
    }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章