第7章习题 使用关联容器

1

1.1 统计单词个数

//统计单词个数
#include <iostream>
#include <map>
#include <string>

using std::cin; using std::cout;
using std::endl;
using std::map; using std::string;

int main(int argc, char const *argv[]){
    string s;
    map<string, int>counters;

    while(cin >> s)
        ++counters[s];

        for (map<string,int>::const_iterator it = counters.begin(); it != counters.end(); ++it) {
            cout << it->first <<"\t" << it->second <<endl;
        }

    return  0;
}

1.2 统计单词出现的行数

//统计单词出现的行数
#include <iostream>
#include <map>
#include <string>
#include <vector>
#include <cctype>

using std::cin; using std::cout;
using std::endl;
using std::map; using std::string;
using std::vector; using std::istream;

//是空白区域为true
bool space(char c){
    return isspace(c);
}
//不是空白区域为true
bool not_space(char c){
    return  !isspace(c);
}

vector<string> split(const string& str){
    typedef string::const_iterator iter;
    vector<string> ret;
    iter i = str.begin();
    while(i != str.end()){
        //忽略前面的空白
        i = find_if(i, str.end(), not_space);
        //找到下一个单词的结尾
        iter j = find_if(i , str.end(), space);
        //复制在[i,j)中的字符
        if(i != str.end()){
            ret.push_back(string(i, j));
        }
        i = j;
    }
    return  ret;
}

map<string, vector<int> > xref(istream& in, vector<string> find_words(const string&) = split){
    string line;
    int line_number = 0;
    map<string, vector<int> > ret;
    while(getline(in, line)){
        ++line_number;

        vector<string> words = find_words(line);

        for (vector<string>::const_iterator it = words.begin(); it != words.end(); ++it) {
            vector<int>::const_iterator it2;
            for (it2 = ret[*it].begin(); it2 != ret[*it].end(); ++it2) {
                if(*it2 == line_number){
                    break;
                }
            }
            if(it2 == ret[*it].end()){
                ret[*it].push_back(line_number);
            }

        }
    }
    return  ret;
}

int main(int argc, char const *argv[]){
    map<string, vector<int> > ret = xref(cin);
    for (map<string, vector<int> >::const_iterator it = ret.begin(); it != ret.end(); ++it) {
        cout << it->first << " occurs on line(s): ";

        vector<int>::const_iterator line_it = it->second.begin();
        cout << *line_it;

        ++line_it;
        while(line_it != it->second.end()){
            cout << " , " << (*line_it);
            line_it++;
        }
        cout << endl;
    }
    return  0;
}

1.3 造句

//造句
#include <iostream>
#include <map>
#include <string>
#include <vector>
#include <cctype>
#include <stdexcept>
#include <cstdlib>

using std::cin; using std::cout;
using std::endl;
using std::map; using std::string;
using std::vector; using std::istream;
using std::logic_error;
using std::domain_error;

typedef vector<string> Rule;
typedef vector<Rule> Rule_collection;
typedef map<string, Rule_collection> Grammar;

//是空白区域为true
bool space(char c){
    return isspace(c);
}
//不是空白区域为true
bool not_space(char c){
    return  !isspace(c);
}

vector<string> split(const string& str){
    typedef string::const_iterator iter;
    vector<string> ret;
    iter i = str.begin();
    while(i != str.end()){
        //忽略前面的空白
        i = find_if(i, str.end(), not_space);
        //找到下一个单词的结尾
        iter j = find_if(i , str.end(), space);
        //复制在[i,j)中的字符
        if(i != str.end()){
            ret.push_back(string(i, j));
        }
        i = j;
    }
    return  ret;
}

Grammar read_grammar(istream& in){
    Grammar ret;
    string line;
    while(getline(in, line)){
        //将输入分割成单个单词
        vector<string> entry = split(line);

        if(!entry.empty()){
            //用类型来存储相关联的规则
            ret[entry[0]].push_back(Rule(entry.begin()+1, entry.end()));
        }
    }
    return ret;
}

bool backeted(const string& s){
    return  s.size() > 1 && s[0] == '<' && s[s.size() - 1] == '>';
}

int nrand(int n){
    if(n <= 0 || n > RAND_MAX){
        throw domain_error("Argument to nrand is out of range");
    }
    const int bucket_size = RAND_MAX / n;
    int r;

    do{
        r = rand()/bucket_size;
    }while(r >= n);

    return r;

}

void gen_aux(const Grammar& g, const string& word, vector<string>& ret){
    if(!backeted(word)){
        ret.push_back(word);
    }else{
        //为对应的word规则定位
        Grammar::const_iterator it = g.find(word);
        if(it == g.end()){
            throw logic_error("empty rule");
        }
        //获取可能的规则
        const Rule_collection& c = it->second;//进入到vector<vector<string>>
        //从规则集合中随机选择一条规则
        const Rule& r = c[nrand(c.size())];//到vector<string>

        for (Rule::const_iterator i = r.begin(); i != r.end(); ++i) {
            gen_aux(g, *i, ret);
        }
    }
}

vector<string> gen_sentence(const Grammar& g){
    vector<string> ret;
    //展开第二个参数传递过来的字符串
    //在第一个参数的文法(语句结构)中查找这个字符串并将它的输出放在第三个参数中
    gen_aux(g, "<sentence>", ret);
    return ret;
}

int main(int argc, char const *argv[]){
    vector<string> sentence = gen_sentence((read_grammar(cin)));

    vector<string>::const_iterator it = sentence.begin();
    if(!sentence.empty()){
        cout << *it;
        ++it;
    }
    while(it != sentence.end()){
        cout <<" " <<*it;
        ++it;
    }
    cout << endl;
    return  0;
}
/*
<sentence> the <nm> <v> <p>
<nm> <n>
<nm> <a> <nm>
<n> cat
<n> dog
<a> large
<a> absurd
<v> sits
<v> jumps
<p> on te stairs
<p> under the sky
 */

1 桉单词出现的次数从小到大输出单词

1.1 法一

#include <iostream>
using std::cin; using std::cout;
using std::endl;

#include <string>
using std::string;

#include <map>
using std::map;

#include <vector>
using std::vector;

#include <cstddef>
using std::size_t ;

int main(int argc, char **argv){
    string s;
    map<string, int> counters;
    vector<string> wordSet[100];
    size_t maxcount = 1;
    while(cin >> s){
        ++counters[s];
        wordSet[counters[s]].push_back(s);
        if(counters[s] > maxcount) maxcount = counters[s];
    }

    for (vector<string>::size_type i = 1; i != maxcount; ++i) {
        for (vector<string>::size_type j = 0; j != wordSet[i].size(); ++j) {
            if(j != 0) cout << " ";
            cout << wordSet[i][j];
        }
        if(wordSet[i].size() != 0) cout <<endl;
    }

    return 0;
}

1.2 法二

先用map<sring,int>映射表统计单词出现的次数,然后把map的数组转换成pair<int,string>存入multimap(一个键可以对应多个值)中,然后输出。

#include <iostream>
using std::cin; using std::cout;
using std::endl;
using std::istream;
using std::ostream;
#include <string>
using std::string;

#include <map>
using std::map;
using std::multimap;

#include <algorithm>
using std::transform;

#include <iterator>
using std::inserter;

#include <utility>
using std::pair;

pair<int, string> deal_pair(pair<string, int> p){
    return pair<int, string > (p.second, p.first);
}


istream& counters_sort(istream& is, ostream& os){
    string s;
    map<string, int> counters;
    multimap<int, string> ans;
    while(cin >> s){
        ++counters[s];
    }
    //对counters数组按值从小到大排序
    transform(counters.begin(), counters.end(), inserter(ans, ans.begin()), deal_pair);

    for (multimap<int, string>::const_iterator it = ans.begin(); it != ans.end() ; ++it) {
        os << it->second << "\t" << it->first <<endl;
    }
    return  is;
}


int main(int argc, char **argv){
    if(counters_sort(cin, cout)){
        return 0;
    }else{
        return 1;
    }
}

2 按分数评出等级

头文件:
Student_info.h

#ifndef ACM_Student_info
#define ACM_Student_info

#include <iostream>
#include <string>
#include <vector>

struct Student_info{
    std::string name;
    double midterm, final;
    std::vector<double> homework;

};

bool compare(const Student_info&, const Student_info&);

std::istream& read_hw(std::istream&, std::vector<double>&);
std::istream& read(std::istream&, Student_info&);


#endif

grade.h

#ifndef ACM_GRADE_H
#define ACM_GRADE_H

#include<vector>
#include"Student_info.h"
double grade(double, double, double);
double grade(double, double, const std::vector<double>&);
double grade(const Student_info&);

#endif

#include <algorithm>
#include <iomanip>
#include <ios>
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>
#include "grade.h"//grade函数重载声明
#include "Student_info.h"//与Student_info结构和相关的函数组装起来
#include <map>
#include <fstream>

using std::cin;             using std::setprecision;
using std::cout;            using std::sort;
using std::domain_error;    using std::streamsize;
using std::string;          using std::vector;
using std::max;             using std::endl;
using std::istream;

//按照字母顺序排列学生
bool compare(const Student_info& x, const Student_info& y){
    return x.name < y.name;
}

//求中位数
double median(vector<double> vec){
    typedef vector<double>::size_type vec_sz;

    vec_sz  size = vec.size();
    if(size == 0)
        throw domain_error ("median of an empty vector");

    sort(vec.begin(), vec.end());

    vec_sz  mid = size/2;

    return size % 2 == 0 ? (vec[mid] + vec[mid-1])/2 : vec[mid];
}

//对Stundet_info类型的对象进行处理
double grade(const Student_info& s){
    return grade(s.midterm, s.final, s.homework);//调用grade2
}//grade1


//根据期中、期末以及保存家庭作业的向量来计算学生的总成绩
double grade(double midterm, double final, const vector<double>& hw){
    if(hw.size() == 0)
        throw  domain_error("student has done no homework");
    return grade(midterm, final, median(hw));//如果家庭作业非空,则调用grade3
}//grade2

//根据期中、期末、平时成绩计算总成绩
double  grade(double midterm, double final, double homework){
    return 0.2 * midterm + 0.4 * final + 0.4 * homework;
}//garde3

//读入学生姓名、期中、期末成绩、家庭作业成绩
istream& read(istream& is, Student_info& s){
    is >> s.name >> s.midterm >> s.final;
    //如果输入的期中、期末成绩不是数字,则会把输入流标记为失败状态

    read_hw(is, s.homework);//读入家庭作业
    return is;
}

//从输入流中将家庭作业的成绩读入到一个vector<double>中
istream& read_hw(istream& in, vector<double>& hw){
    if(in){//当前学生的姓名、期中期末成绩非法时(输入流标记为失败状态),不会读入家庭作业
        //清除原先内容
        hw.clear();//清除之前可能存在的成绩,重新再次拥有空向量

        double x;
        while(in >> x){//输入的不是成绩时,库把输入流标记为失败状态
            hw.push_back(x);
        }
        //清除流使得输入动作对下个学生有效
        in.clear();//清除所有错误标记使得输入动作可以继续,并不清除下一个存储在输入流中的姓名
    }//如正常读完in,则返回in正确标记
    return in;
}


int main(){
    vector<Student_info> students;
    Student_info record;
    string::size_type maxlen = 0;//最长姓名的长度

    string file = "/Users/macbookpro/CLionProjects/ACM/students10000.txt";
    std::ifstream infile;
    infile.open(file);

    //读入并存储所有学生的数据
    while(read(infile,record)){//遇到非法输入,则结束输入,例如读入两个姓名
        //找出最长姓名的长度
        maxlen = max(maxlen, record.name.size());
        students.push_back(record);
    }
    infile.close();
    infile.clear();

    //按字母顺序排列学生记录
    sort(students.begin(), students.end(), compare);
//统计不同等级的学生个数
    std::map<string, int> counters;

    //输出学生姓名和成绩
    for (vector<Student_info>::size_type i = 0; i != students.size() ; ++i) {
        //输出姓名,将姓名填充值maxlen+1个字符的长度
        cout << students[i].name
             <<  string(maxlen + 1 - students[i].name.size(),' ');

        //计算并输出成绩
        try {

            double final_grade = grade(students[i]);//调用grade2

            if(final_grade >= 90.0){
                counters["A"]++;
            }else if(final_grade >= 80.0 && final_grade < 90.0){
                counters["B"]++;
            }else if(final_grade >= 70.0 && final_grade < 80.0){
                counters["C"]++;
            }else if(final_grade >= 60.0 && final_grade < 70.0){
                counters["D"]++;
            }else{
                counters["F"]++;
            }

            streamsize pre = cout.precision();
            cout << setprecision(3) << final_grade
                 << setprecision(pre);
        }catch (domain_error e){
            cout << e.what();
        }
        cout << endl;
    }

    for (std::map<string, int>::const_iterator it = counters.begin(); it != counters.end() ; ++it) {
        cout << it->first << "\t" << it->second <<endl;
    }

    return 0;
}

3 单词在同一行出现多次,只插入这个行编号一次

3.1 法一

//统计单词出现的行数
#include <iostream>
#include <map>
#include <string>
#include <vector>
#include <cctype>

using std::cin; using std::cout;
using std::endl;
using std::map; using std::string;
using std::vector; using std::istream;

//是空白区域为true
bool space(char c){
    return isspace(c);
}
//不是空白区域为true
bool not_space(char c){
    return  !isspace(c);
}

vector<string> split(const string& str){
    typedef string::const_iterator iter;
    vector<string> ret;
    iter i = str.begin();
    while(i != str.end()){
        //忽略前面的空白
        i = find_if(i, str.end(), not_space);
        //找到下一个单词的结尾
        iter j = find_if(i , str.end(), space);
        //复制在[i,j)中的字符
        if(i != str.end()){
            ret.push_back(string(i, j));
        }
        i = j;
    }
    return  ret;
}

map<string, vector<int> > xref(istream& in, vector<string> find_words(const string&) = split){
    string line;
    int line_number = 0;
    map<string, vector<int> > ret;
    while(getline(in, line)){
        ++line_number;

        vector<string> words = find_words(line);

        for (vector<string>::const_iterator it = words.begin(); it != words.end(); ++it) {
            vector<int>::const_iterator it2;
            //边面一行出现的同一个单词,输出多次
            for (it2 = ret[*it].begin(); it2 != ret[*it].end(); ++it2) {
                if(*it2 == line_number){
                    break;
                }
            }
            if(it2 == ret[*it].end()){
                ret[*it].push_back(line_number);
            }

        }
    }
    return  ret;
}

int main(int argc, char const *argv[]){
    map<string, vector<int> > ret = xref(cin);
    for (map<string, vector<int> >::const_iterator it = ret.begin(); it != ret.end(); ++it) {
        cout << it->first << " occurs on line(s): ";

        vector<int>::const_iterator line_it = it->second.begin();
        cout << *line_it;

        ++line_it;
        while(line_it != it->second.end()){
            cout << " , " << (*line_it);
            line_it++;
        }
        cout << endl;
    }
    return  0;
}

3.2 法二

//统计单词出现的行数
#include <iostream>
#include <map>
#include <string>
#include <vector>
#include <cctype>
#include <iterator>
using std::distance;
#include <algorithm>
using std::unique;

using std::cin; using std::cout;
using std::endl;
using std::map; using std::string;
using std::vector; using std::istream;

//是空白区域为true
bool space(char c){
    return isspace(c);
}
//不是空白区域为true
bool not_space(char c){
    return  !isspace(c);
}

vector<string> split(const string& str){
    typedef string::const_iterator iter;
    vector<string> ret;
    iter i = str.begin();
    while(i != str.end()){
        //忽略前面的空白
        i = find_if(i, str.end(), not_space);
        //找到下一个单词的结尾
        iter j = find_if(i , str.end(), space);
        //复制在[i,j)中的字符
        if(i != str.end()){
            ret.push_back(string(i, j));
        }
        i = j;
    }
    return  ret;
}

map<string, vector<int> > xref(istream& in, vector<string> find_words(const string&) = split){
    string line;
    int line_number = 0;
    map<string, vector<int> > ret;
    while(getline(in, line)) {
        ++line_number;

        vector<string> words = find_words(line);
        //法一
//        for (vector<string>::const_iterator it = words.begin(); it != words.end(); ++it) {
//            vector<int>::const_iterator it2;
//            //边面一行出现的同一个单词,输出多次
//            for (it2 = ret[*it].begin(); it2 != ret[*it].end(); ++it2) {
//                if(*it2 == line_number){
//                    break;
//                }
//            }
//            if(it2 == ret[*it].end()){
//                ret[*it].push_back(line_number);
//            }
//
//        }
//    }
        //法二
        for (vector<string>::const_iterator it = words.begin(); it != words.end(); ++it) {
            ret[*it].push_back(line_number);
        }

        //unique:是把重复的元素移到后面去了,然后返回不重复元素的最后一个的迭代器
        //resize:截断向量长度
        //distance:返回区间长度
        for (map<string, vector<int>>::iterator it = ret.begin(); it != ret.end(); ++it) {
            it->second.resize(std::distance(it->second.begin(), unique(it->second.begin(), it->second.end())));
        }
    }
    
    return  ret;
}

int main(int argc, char const *argv[]){
    map<string, vector<int> > ret = xref(cin);
    for (map<string, vector<int> >::const_iterator it = ret.begin(); it != ret.end(); ++it) {
        cout << it->first << " occurs on line(s): ";

        vector<int>::const_iterator line_it = it->second.begin();
        cout << *line_it;

        ++line_it;
        while(line_it != it->second.end()){
            cout << " , " << (*line_it);
            line_it++;
        }
        cout << endl;
    }
    return  0;
}

4 行太长换行输出

//统计单词出现的行数
#include <iostream>
#include <map>
#include <string>
#include <vector>
#include <cctype>
#include <iterator>
using std::distance;
#include <algorithm>
using std::unique;

using std::cin; using std::cout;
using std::endl;
using std::map; using std::string;
using std::vector; using std::istream;

//是空白区域为true
bool space(char c){
    return isspace(c);
}
//不是空白区域为true
bool not_space(char c){
    return  !isspace(c);
}

vector<string> split(const string& str){
    typedef string::const_iterator iter;
    vector<string> ret;
    iter i = str.begin();
    while(i != str.end()){
        //忽略前面的空白
        i = find_if(i, str.end(), not_space);
        //找到下一个单词的结尾
        iter j = find_if(i , str.end(), space);
        //复制在[i,j)中的字符
        if(i != str.end()){
            ret.push_back(string(i, j));
        }
        i = j;
    }
    return  ret;
}

map<string, vector<int> > xref(istream& in, vector<string> find_words(const string&) = split){
    string line;
    int line_number = 0;
    map<string, vector<int> > ret;
    while(getline(in, line)) {
        ++line_number;

        vector<string> words = find_words(line);

        for (vector<string>::const_iterator it = words.begin(); it != words.end(); ++it) {
            ret[*it].push_back(line_number);
        }

        //unique:是把重复的元素移到后面去了,然后返回不重复元素的最后一个的迭代器
        for (map<string, vector<int>>::iterator it = ret.begin(); it != ret.end(); ++it) {
            it->second.resize(std::distance(it->second.begin(), unique(it->second.begin(), it->second.end())));
        }
    }

    return  ret;
}

int main(int argc, char const *argv[]){
    map<string, vector<int> > ret = xref(cin);

    int linLength = 60;
    for (map<string, vector<int> >::const_iterator it = ret.begin(); it != ret.end(); ++it) {
        string s = it->first + " occurs on line(s): ";
        //换行输出时用,为了对其
        string s_spaces(s.size(), ' ');

        vector<int>::const_iterator line_it = it->second.begin();

        while(line_it != it->second.end()){
            //数据出现的行数
            string data = std::to_string(*line_it);
            //累加数据
            if(line_it != it->second.end() - 1){
                data += ", ";
            }
            //超过规定的长度,换行输出
            if(s.size() + data.size() > linLength){
                cout << s << endl;
                s = s_spaces + data;
            }else{//没超过规定长度,继续累加
                s += data;
            }
            ++line_it;
        }
        //把没有输出的数据输出
        if(s.size() > s_spaces.size()){
            cout << s << endl;
        }

        cout << endl;
    }

    return  0;
}

5 用链表实现造句程序

//造句
#include <iostream>
#include <map>
#include <string>
#include <vector>
#include <cctype>
#include <stdexcept>
#include <cstdlib>
#include <list>

using std::cin; using std::cout;
using std::endl;
using std::map; using std::string;
using std::vector; using std::istream;
using std::logic_error;
using std::domain_error;
using std::list;

typedef vector<string> Rule;
typedef vector<Rule> Rule_collection;
typedef map<string, Rule_collection> Grammar;

//是空白区域为true
bool space(char c){
    return isspace(c);
}
//不是空白区域为true
bool not_space(char c){
    return  !isspace(c);
}

list<string> split(const string& str){
    typedef string::const_iterator iter;
    list<string> ret;
    iter i = str.begin();
    while(i != str.end()){
        //忽略前面的空白
        i = find_if(i, str.end(), not_space);
        //找到下一个单词的结尾
        iter j = find_if(i , str.end(), space);
        //复制在[i,j)中的字符
        if(i != str.end()){
            ret.push_back(string(i, j));
        }
        i = j;
    }
    return  ret;
}

Grammar read_grammar(istream& in){
    Grammar ret;
    string line;
    while(getline(in, line)){
        //将输入分割成单个单词
        list<string> entry = split(line);

        if(!entry.empty()){
            //用类型来存储相关联的规则
            //改变
            ret[entry.front()].push_back(Rule(++entry.begin(), entry.end()));
        }
    }
    return ret;
}

bool backeted(const string& s){
    return  s.size() > 1 && s[0] == '<' && s[s.size() - 1] == '>';
}

int nrand(int n){
    if(n <= 0 || n > RAND_MAX){
        throw domain_error("Argument to nrand is out of range");
    }
    const int bucket_size = RAND_MAX / n;
    int r;

    do{
        r = rand()/bucket_size;
    }while(r >= n);

    return r;

}

void gen_aux(const Grammar& g, const string& word, list<string>& ret){
    if(!backeted(word)){
        ret.push_back(word);
    }else{
        //为对应的word规则定位
        Grammar::const_iterator it = g.find(word);
        if(it == g.end()){
            throw logic_error("empty rule");
        }
        //获取可能的规则
        const Rule_collection& c = it->second;//进入到vector<vector<string>>
        //从规则集合中随机选择一条规则
        const Rule& r = c[nrand(c.size())];//到vector<string>

        for (Rule::const_iterator i = r.begin(); i != r.end(); ++i) {
            gen_aux(g, *i, ret);
        }
    }
}

list<string> gen_sentence(const Grammar& g){
    list<string> ret;
    //展开第二个参数传递过来的字符串
    //在第一个参数的文法(语句结构)中查找这个字符串并将它的输出放在第三个参数中
    gen_aux(g, "<sentence>", ret);
    return ret;
}

int main(int argc, char const *argv[]){
    list<string> sentence = gen_sentence((read_grammar(cin)));

    list<string>::const_iterator it = sentence.begin();
    if(!sentence.empty()){
        cout << *it;
        ++it;
    }
    while(it != sentence.end()){
        cout <<" " <<*it;
        ++it;
    }
    cout << endl;
    return  0;
}
/*
<sentence> the <nm> <v> <p>
<nm> <n>
<nm> <a> <nm>
<n> cat
<n> dog
<a> large
<a> absurd
<v> sits
<v> jumps
<p> on te stairs
<p> under the sky
 */

6 使用栈实现gen_sentence程序

//造句
#include <iostream>
#include <map>
#include <string>
#include <vector>
#include <cctype>
#include <stdexcept>
#include <cstdlib>

using std::cin; using std::cout;
using std::endl;
using std::map; using std::string;
using std::vector; using std::istream;
using std::logic_error;
using std::domain_error;

typedef vector<string> Rule;
typedef vector<Rule> Rule_collection;
typedef map<string, Rule_collection> Grammar;

//是空白区域为true
bool space(char c){
    return isspace(c);
}
//不是空白区域为true
bool not_space(char c){
    return  !isspace(c);
}

vector<string> split(const string& str){
    typedef string::const_iterator iter;
    vector<string> ret;
    iter i = str.begin();
    while(i != str.end()){
        //忽略前面的空白
        i = find_if(i, str.end(), not_space);
        //找到下一个单词的结尾
        iter j = find_if(i , str.end(), space);
        //复制在[i,j)中的字符
        if(i != str.end()){
            ret.push_back(string(i, j));
        }
        i = j;
    }
    return  ret;
}

Grammar read_grammar(istream& in){
    Grammar ret;
    string line;
    while(getline(in, line)){
        //将输入分割成单个单词
        vector<string> entry = split(line);

        if(!entry.empty()){
            //用类型来存储相关联的规则
            ret[entry[0]].push_back(Rule(entry.begin()+1, entry.end()));
        }
    }
    return ret;
}

bool backeted(const string& s){
    return  s.size() > 1 && s[0] == '<' && s[s.size() - 1] == '>';
}

int nrand(int n){
    if(n <= 0 || n > RAND_MAX){
        throw domain_error("Argument to nrand is out of range");
    }
    const int bucket_size = RAND_MAX / n;
    int r;

    do{
        r = rand()/bucket_size;
    }while(r >= n);

    return r;

}

vector<string> gen_sentence(const Grammar& g){
    vector<string> ret;
    //展开第二个参数传递过来的字符串
    //在第一个参数的文法(语句结构)中查找这个字符串并将它的输出放在第三个参数中
//    gen_aux(g, "<sentence>", ret);
    vector<string> rules;

    rules.push_back("<sentence>");
    while(!rules.empty()){
        string segment = rules.back();
        rules.pop_back();

        if(!backeted(segment)){
            ret.push_back(segment);
        }else{
            //为对应的word规则定位
            Grammar::const_iterator it = g.find(segment);

            if (it == g.end())
                throw logic_error("empty rule");

            //获取可能的规则
            const Rule_collection& c = it->second;//进入到vector<vector<string>>
            //从规则集合中随机选择一条规则
            const Rule& r = c[nrand(c.size())];//到vector<string>
            //到这存储
            for (Rule::const_reverse_iterator i = r.rbegin(); i != r.rend(); ++i) {
                rules.push_back(*i);
            }
        }
    }

    return ret;
}

int main(int argc, char const *argv[]){
    vector<string> sentence = gen_sentence((read_grammar(cin)));

    vector<string>::const_iterator it = sentence.begin();
    if(!sentence.empty()){
        cout << *it;
        ++it;
    }
    while(it != sentence.end()){
        cout <<" " <<*it;
        ++it;
    }
    cout << endl;
    return  0;
}
/*
<sentence> the <nm> <v> <p>
<nm> <n>
<nm> <a> <nm>
<n> cat
<n> dog
<a> large
<a> absurd
<v> sits
<v> jumps
<p> on te stairs
<p> under the sky
 */

7 只有一行的输出line,多行的输出lines

//统计单词出现的行数
#include <iostream>
#include <map>
#include <string>
#include <vector>
#include <cctype>
#include <algorithm>
#include <iterator>

using std::cin; using std::cout;
using std::endl;
using std::map; using std::string;
using std::vector; using std::istream;

//是空白区域为true
bool space(char c){
    return isspace(c);
}
//不是空白区域为true
bool not_space(char c){
    return  !isspace(c);
}

vector<string> split(const string& str){
    typedef string::const_iterator iter;
    vector<string> ret;
    iter i = str.begin();
    while(i != str.end()){
        //忽略前面的空白
        i = find_if(i, str.end(), not_space);
        //找到下一个单词的结尾
        iter j = find_if(i , str.end(), space);
        //复制在[i,j)中的字符
        if(i != str.end()){
            ret.push_back(string(i, j));
        }
        i = j;
    }
    return  ret;
}

map<string, vector<int> > xref(istream& in, vector<string> find_words(const string&) = split){
    string line;
    int line_number = 0;
    map<string, vector<int> > ret;
    while(getline(in, line)) {
        ++line_number;

        vector<string> words = find_words(line);

        for (vector<string>::const_iterator it = words.begin(); it != words.end(); ++it) {
            ret[*it].push_back(line_number);
        }

    }

    return  ret;
}

int main(int argc, char const *argv[]){
    map<string, vector<int> > ret = xref(cin);
    map<string, string> ans;

    for (map<string, vector<int> >::iterator it = ret.begin(); it != ret.end() ; ++it) {
        string count= it->second.size() > 1 ? "lines" : "line";
        cout << it->first <<" occurs on line(s): "<< count << endl;
    }

    return  0;
}

8 查找文件中URL出现的全部行

//找统一资源地址
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <cctype>
#include <map>
#include <numeric>
#include <fstream>
#import <iterator>

using std::accumulate;
using std::cin; using std::cout;
using std::endl;
using std::string; using std::vector;
using std::equal; using std::search;
using std::find_if;
using std::map;
using std::multimap;

//没找到字符,返回true
bool not_url_char(char c){
    //除数字字母外可能,其他可能出现的URL中的字符
    static const string url_ch = "~;!@#$%^&*()_+/'?.=&-:";
    //查看c是够出现在一个URl中并返回求反的值
    return !(isalnum(c)|| find(url_ch.begin(), url_ch.end(),c) != url_ch.end());
}

string::const_iterator url_end(string::const_iterator b, string::const_iterator e){
    return  find_if(b, e, not_url_char);
}

string::const_iterator url_beg(string::const_iterator b, string::const_iterator e){
    static const string sep = "://";

    typedef string::const_iterator iter;
    //i标记了查找到的分隔符的位置
    iter i = b;

    i = search(i ,e , sep.begin(), sep.end());
    //如果找到会返回//之前的位置,没有找到会返回输入字符串的末尾之后的那个位置
    while(i != e){
        //分隔符是否填满整行,://前面有字符串以及://后面至少有一个字符
        if(i != b && i + sep.size() != e){
            //beg标记协议名称的开头
            iter beg = i;
            //一直碰到第一个非字母或者字符串开头为止
            while(beg != b && isalpha(beg[-1])){
                --beg;
            }
            //是够在分隔符前面以及后面至少有一个字符
            if(beg != i && !not_url_char(i[sep.size()])){
                return  beg;
            }
        }
        //找到的分割符不是URL的一部分
        i += sep.size();
    }
    return  e;
}

vector<string> find_urls(const string& s){
    vector<string> ret;
    typedef string::const_iterator iter;
    iter b = s.begin(), e = s.end();

    //检查整个输入
    while(b != e){
        //查找下一个或多个紧跟着://的字母
        b = url_beg(b, e);
        //查找成功
        if(b != e){
            //获取url其余部分
            iter after = url_end(b, e);
            //记住这个url
            ret.push_back(string(b,after));
            //将b向前推进并查找本行中的其他url
            b = after;
        }
    }
    return ret;
}

//分割字符串
vector<string> split(const string& s){
    vector<string> ret;
    typedef string::size_type string_size;
    string_size  i = 0;

    while(i != s.size()){
        //忽略前段的空白:[先前的i,i)中全部字符都是空格
        while(i != s.size() && isspace(s[i])){
            i++;
        }
        //找出下一个单词的终结点
        string_size j = i;
        //[先前的j,j)中的任意字符都不是空格
        while(j != s.size() && !isspace(s[j])){
            j++;
        }
        //找到了一些非空白符
        if(i != j){
            ret.push_back(s.substr(i, j - i));
            i = j;
        }
    }
    return ret;
}

int main(int argc, char const *argv[]){

    string file = "/Users/macbookpro/CLionProjects/ACM/infile.txt";
    std::ifstream infile;
    infile.open(file);

    string str;
    size_t line_number = 1;
    map<string, vector<int>> ret;

    while(getline(infile, str)){
        vector<string> res = split(str);
        vector<string> str_url;

        for (vector<string>::const_iterator it = res.begin(); it != res.end(); ++it) {
            str_url = find_urls(*it);
        }

        for (vector<string>::const_iterator it = str_url.begin(); it != str_url.end(); ++it) {
            ret[*it].push_back(line_number);
        }
        line_number++;
    }
    
    for (map<string, vector<int>>::iterator it = ret.begin(); it != ret.end(); ++it) {
        it->second.resize(std::distance(it->second.begin(), std::unique(it->second.begin(), it->second.end())));
    }

    for (map<string, vector<int>>::iterator it = ret.begin(); it != ret.end(); ++it) {
        cout << it->first << " occurs on line(s): ";

        vector<int>::const_iterator line_it = it->second.begin();

        cout << *line_it;

        ++line_it;
        while(line_it != it->second.end()){
            cout << " , " << (*line_it);
            line_it++;
        }
        cout << endl;
    }

    return  0;
}

9 优化nrand函数

#include <iostream>
using std::cin; using std::cout;
using std::endl;
using std::istream;
using std::ostream;
#include <string>
using std::string;

#include <iterator>
using std::inserter;

#include <exception>
using std::domain_error;

int nrand_improved(int n, const int max = RAND_MAX) {

    if (n <= 0)
        throw domain_error("Argument to nrand is out of range");

    if (n <= max)
    {
        const int bucket_size = max / n;
        int r;

        do r = rand() / bucket_size;
        while (r >= n);

        return r;
    }
    else
    {
        const int buckets = n / max;
        const int remainder_rand = n % max == 0 ? 0 : nrand_improved(n % max);
        const int lost = n % max == 0 ? buckets : buckets + 1;

        return nrand_improved(max) * buckets + remainder_rand + nrand_improved(lost);
    }
}

int main(int argc, char** argv)
{
    for (int i = 0; i < 100; i++){
        cout << nrand_improved(100, 3) << endl;
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

繁星蓝雨

如果觉得文章不错,可以请喝咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值