第6章习题 使用C++库算法

1

1.1 分割字符串

//分离字符串
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <cctype>

using std::cin; using std::cout;
using std::endl;
using std::string; using std::vector;
using std::find_if;
//是空白区域为true
bool space(char c){
    return isspace(c);
}
//不是空白区域为true
bool not_space(char c){
    return  !isspace(c);
}

vector<string> split2(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;
}

//分割字符串
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 s;
    while(cin >> s){
        vector<string> v = split(s);
        for (vector<string>::size_type i = 0; i != v.size(); ++i) {
            cout << v[i] <<endl;
        }
    }
    return  0;
}

1.2 判回文

//判回文
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>

using std::cin; using std::cout;
using std::endl;
using std::string; using std::vector;
using std::equal;

bool is_pailndrome(const string& s){
    //s.rbegin()返回最后一个元素,并逆向向前访问
    return  equal(s.begin(), s.end(), s.rbegin());
    //第一、二个参数为第一个序列,第三个参数无诶第二序列的起点
}

int main(int argc, char const *argv[]){
    string s;
    while(cin >> s){
        if(is_pailndrome(s)){
            cout << "Yes" <<endl;
        }else{
            cout <<"No" <<endl;
        }
    }
    return  0;
}

1.3 寻找URL

//找统一资源地址
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <cctype>

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;

//没找到字符,返回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;
}

int main(int argc, char const *argv[]){
    string s;
//    while(cin >> s){
        cin >> s;
        vector<string> res = find_urls(s);
        for (vector<string>::const_iterator it = res.begin(); it != res.end(); ++it) {
            cout << (*it) << endl;
        }
//    }
    return  0;
}

1.4 计算成绩

头文件
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

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;
//    double score;

};

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

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


#endif
#include <iostream>
#include <algorithm>
#include <vector>
#include "Student_info.h"
#include "grade.h"
#include <stdexcept>
#include <numeric>
#include <string>
#include <ostream>
using std::cin; using std::cout;
using std::endl;
using std::vector; using std::transform;
using std::domain_error; using std::string;
using std::ostream; using std::transform;
using std::istream;

bool did_all_hw(const Student_info& s){
    return ((find(s.homework.begin(), s.homework.end(),0)) == s.homework.end());
}

//求中位数
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

//重写便于transform调用,解决学生家庭成绩为0 的情况
double grade_aux(const Student_info& s){
    try{
        return grade(s);
    }catch (domain_error){
        return grade(s.midterm, s.final, 0);
    }
}

double median_analysis(const vector<Student_info>& students){
    vector<double > grades;
    transform(students.begin(), students.end(), back_inserter(grades), grade_aux);
    return  median(grades);
}


//计算向量平均值
double average(const vector<double >& v){
    return  accumulate(v.begin(), v.end(), 0) / v.size();
}

//计算单个学生成绩,用平均值代替中值
double average_grade(const Student_info& s){
    return grade(s.midterm, s.final, average((s.homework)));
}

//计算家庭作业平均成绩的总成绩
double average_analysis(const vector<Student_info>& students){
    vector<double > grades;
    transform(students.begin(), students.end(), back_inserter(grades), average_grade);
    return median(grades);
}

//计算单个学生成绩,计算实际上交作业的中值
double optimistic_median(const Student_info& s){
    vector<double > nonzero;
    std::remove_copy(s.homework.begin(), s.homework.end(), back_inserter(nonzero), 0);
    if(nonzero.empty()){
        return grade(s.midterm, s.final, 0);//学生一次作业都没有做
    }else{
        return grade(s.midterm, s.final, median(nonzero));
    }
}
//计算乐观成绩中值
double optimistic_median_analysis(const vector<Student_info>& students){
    vector<double > grades;
    transform(students.begin(), students.end(), back_inserter(grades), optimistic_median);
    return median(grades);
}

//读入学生姓名、期中、期末成绩、家庭作业成绩
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;
}

//函数作为参数传递,分析比较两个学生的集合,全做家庭作业的和漏交家庭作业的
void write_analysis(ostream& out, const string& name,
                    double analysis(const vector<Student_info>&), const vector<Student_info>&did,
                    const vector<Student_info>& didnt){
    out << name <<":median(did) = " << analysis(did)
        <<",median(didnt) = " << analysis(didnt) << endl;
}


int main(int argc, char const *argv[]){
    vector<Student_info> did, didnt;

    Student_info student;
    while(read(cin, student)){
        if(did_all_hw(student)){
            did.push_back(student);
        }else{
            didnt.push_back(student);
        }
    }

    if(did.empty()){
        cout << "No students did all the homework!" <<endl;
        return  1;
    }
    if(didnt.empty()){
        cout << "Every student did all the homeword!" <<endl;
    }

    write_analysis(cout, "median", median_analysis, did, didnt);
    write_analysis(cout, "average", average_analysis, did, didnt);
    write_analysis(cout, "median of homework truned in", optimistic_median_analysis, did, didnt);
    return  0;
}

1 使用迭代器重新实现frame函数和hcat函数

#include <iostream>
#include <string>
#include <vector>
#include <list>
#include <algorithm>
#include <cctype>

using  std::cin; using std::endl;
using std::cout; using std::string;
using std::vector; using std::max;




//分割字符串
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;
}


//找出向量中最长字符串的长度
string::size_type width(const vector<string>& v){
    string::size_type  maxlen = 0;
    for (vector<string>::size_type i = 0; i != v.size(); ++i) {
        maxlen = max(maxlen, v[i].size());
    }
    return maxlen;
}

vector<string> frame(const vector<string>& v){
    vector<string> ret;
    string::size_type maxlen = width(v);
    //输出顶部边框
    string border(maxlen + 4, '*');

    //输出内部的行,每行都用一个星号和一个空格来框起来
    ret.push_back(border);
    //使用迭代器实现
    vector<string>::const_iterator iter = v.begin();
    while(iter != v.end()){
        ret.push_back("* " + (*iter) + string(maxlen - iter->size(), ' ') + " *");
        iter++;
    }
//
//    for (vector<string>::size_type i = 0; i != v.size(); ++i) {
//        ret.push_back("* "+ v[i]  + string(maxlen - v[i].size(), ' ') + " *");
//    }
    //输出底部边框
    ret.push_back(border);
    return  ret;
}

//纵向连接
vector<string> vcat(const vector<string>& top, const vector<string>& bottom){
    vector<string> ret = top;
//    for (vector<string>::const_iterator it = bottom.begin(); it != bottom.end() ; ++it) {
//       ret.push_back(*it);
//    }
    //作用同上
    ret.insert(ret.end(), bottom.begin(), bottom.end());
    return  ret;
}

//横向连接
vector<string> hcat(const vector<string>& left, const vector<string>& right){
    vector<string>ret;
    //在两幅图案之间留空格
    string::size_type width1 = width(left) + 1;
    //用于遍历left和right的索引
    //使用迭代器
    vector<string>::const_iterator i, j;
    i = left.begin();
    j = right.begin();
    while(i != left.end() || j != right.end()){
        string s;
        if(i != left.end()){
            s = *i++;
        }

        s += string(width1 - s.size(), ' ');

        if(j != right.end()){
            s += *j++;
        }
        ret.push_back(s);
    }

//    vector<string>::size_type i = 0, j = 0;
//    while(i != left.size() || j != right.size()){
//        string s;
//        //如果左侧图案还有待复制的行,则复制一行
//        if(i != left.size()){
//            s = left[i++];
//        }
//        //填充至适当长度
//        s += string(width1 - s.size(), ' ');
//        //如果右侧还有代复制的行,则复制一行
//        if(j != right.size()){
//            s += right[j++];
//        }
//        ret.push_back(s);
//    }
    return  ret;
}

int main(int argc,const char *argv[]){
    string s;
    while(getline(cin, s)){
        vector<string> v = split(s);
//        for (vector<string>::size_type i = 0; i != v.size(); ++i) {
//            cout << v[i] <<endl;
//        }
        vector<string> fra = frame(v);
        vector<string> col, row;
        col = vcat(v, fra);
        row = hcat(v, fra);
        //打印竖着拼图
//        for (vector<string>::size_type i = 0; i != col.size(); ++i) {
//            cout << col[i] << endl;
//        }
//        //打印横向拼图
        for (vector<string>::size_type j = 0; j != row.size(); ++j) {
            cout << row[j] <<endl;
        }
    }
    return 0;
}

2 编程并测试find_urls函数

//找统一资源地址
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <cctype>

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;

//没找到字符,返回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;
}

int main(int argc, char const *argv[]){
    string s;
//    while(cin >> s){
    cin >> s;
    vector<string> res = find_urls(s);
    for (vector<string>::const_iterator it = res.begin(); it != res.end(); ++it) {
        cout << (*it) << endl;
    }
//    }
    return  0;
}

3 观察下面程序段的用途

用途是:定义一个长度为0,初值为100的向量u(实际上向量u没有任何一个元素),把u中的元素复制到向量v中,但是由于v.begin()不是向量适配器,无法向容器插入值,导致复制失败。就算u中有值,但是下面示例中的copy还是无法将其复制到v中。

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

int main(int argc,const char *argv[]){
    vector<int> u(0, 100);
    //vector<int> u(10, 100);
    vector<int> v;
    copy(u.begin(), u.end(), v.begin());
    for (vector<int>::const_iterator i = v.begin(); i != v.end(); ++i) {
        cout << *i << endl;
    }
    return 0;
}

4 改进3的程序,使之可以是想操作

#include <iostream>
using  std::cin; using std::endl;
using std::cout;
#include <vector>
using std::vector;
#include <algorithm>
using std::copy;
#include <iterator>
using std::back_inserter;
using std::inserter;

int main(int argc,const char *argv[]){
   // vector<int> u(0, 100);
    vector<int> u(1, 100);
    vector<int> v;
    
    //有元素的情况可以插入
 //   vector<int> v(1,11);
//    copy(u.begin(), u.end(), v.begin());

	//使用迭代器适配器
    //改进方法一
    //copy(u.begin(), u.end(), back_inserter(v));
    //改进方法二
    copy(u.begin(), u.end(), inserter(v,v.end()));

    for (vector<int>::const_iterator i = v.begin(); i != v.end(); ++i) {
        cout << *i << endl;
    }
    return 0;
}

5


//计算乐观成绩中值
double optimistic_median_analysis(const vector<Student_info>& students){
    vector<double > grades;
    transform(students.begin(), students.end(), back_inserter(grades), optimistic_median);
    return median(grades);
}
分析函数
//函数作为参数传递,分析比较两个学生的集合,全做家庭作业的和漏交家庭作业的
void write_analysis(ostream& out, const string& name,
                    double analysis(const vector<Student_info>&), const vector<Student_info>&did,
                    const vector<Student_info>& didnt){
    out << name <<":median(did) = " << analysis(did)
        <<",median(didnt) = " << analysis(didnt) << endl;
}

6 把三个分析函数合并成一个单独的函数

也就是把函数作为参数传递给analysis。

double analysis(const vector<Student_info>& students, double grade_deal(const Student_info&)){
    vector<double > grades;
    transform(students.bebgin(), students.end(), back_inserter(grades), grade_deal);
    return median(grades);
}

下面是三个分析函数,每个分析函数除了transform调用的处理函数不同外,其他都相同。

//计算单个学生成绩,计算实际上交作业的中值
double optimistic_median(const Student_info& s){
    vector<double > nonzero;
    std::remove_copy(s.homework.begin(), s.homework.end(), back_inserter(nonzero), 0);
    if(nonzero.empty()){
        return grade(s.midterm, s.final, 0);//学生一次作业都没有做
    }else{
        return grade(s.midterm, s.final, median(nonzero));
    }
}
//计算乐观成绩中值
double optimistic_median_analysis(const vector<Student_info>& students){
    vector<double > grades;
    transform(students.begin(), students.end(), back_inserter(grades), optimistic_median);
    return median(grades);
}

//计算单个学生成绩,用平均值代替中值
double average_grade(const Student_info& s){
    return grade(s.midterm, s.final, average((s.homework)));
}
//计算家庭作业平均成绩的总成绩
double average_analysis(const vector<Student_info>& students){
    vector<double > grades;
    transform(students.begin(), students.end(), back_inserter(grades), average_grade);
    return median(grades);
}

//重写便于transform调用,解决学生家庭成绩为0 的情况
double grade_aux(const Student_info& s){
    try{
        return grade(s);
    }catch (domain_error){
        return grade(s.midterm, s.final, 0);
    }
}

double median_analysis(const vector<Student_info>& students){
    vector<double > grades;
    transform(students.begin(), students.end(), back_inserter(grades), grade_aux);
    return  median(grades);
}

double analysis(const vector<Student_info>& students, double grade_deal(const Student_info&)){
    vector<double > grades;
    transform(students.bebgin(), students.end(), back_inserter(grades), grade_deal);
    return median(grades);
}

7

bool did_all_hw(const Students_info& s){
    return ((find(s.homework.begin(), s.homework.end(), 0)) == s.homework.end());
}

int test_extract(string file){
    vector<Students_info> did, didnt;
    Student_info student;

    iftream infile;
    infile.open(file);
    while(read(infile, student)){
        if(did_all_hw(student)){
            did.push_back(student);
        }else{
            didnt.push_back(student);
        }
    }
    infile.close();
    infile.clear();

    if(did.empty()){
        cout << "No students did all the homework!" <<endl;
        return  1;
    }
    if(didnt.empty()){
        cout << "Every student did all the homeword!" <<endl;
    }
}

8 按照自己的准则分类学生

更改bool类型函数已实现不同的分类:

bool fgrade (const Student_info& s){
    return  grade(s)  < 90;
}
//students保存成绩90分以上的学生,fail保留余下的学生
vector<Student_info> extrac_fail3(vector<Student_info>& students){
    vector<Student_info> fail;
    vector<Student_info>::iterator iter = students.begin();
    while(iter != students.end()){
        if(fgrade(*iter)){
            fail.push_back(*iter);
            iter = students.erase(iter);
        }else{
            ++iter;
        }
    }
    return  fail;
}

9 使用库算法连接一个vector<string>对象中的全部元素

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

#include <numeric>
using std::accumulate;

int main(int argc,const char *argv[]){
   vector<string> v = {"i", "love", "you"};
   string str;
   str = accumulate(v.begin(), v.end(), str);
   cout << str;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

繁星蓝雨

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

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

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

打赏作者

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

抵扣说明:

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

余额充值