第6章 使用库算法
<span style="font-family:KaiTi_GB2312;">for(vector<string>::const_iterator it = bottom.begin(); it != bottom.end(); ++it) ret.push_back(*it);</span></span>
等价于
<span style="font-family:KaiTi_GB2312;">ret.insert(ret.end(), bottom.begin(), bottom.end());</span></span>
也等价于
<span style="font-family:KaiTi_GB2312;">copy(bottom.begin(), bottom.end(), back_inserter(ret));</span></span>
分析:这里指的是复制了bottom中的全部的元素而且把它们加入到ret的末尾。
在这个函数借宿之后。ret的长度将加入bottom.size()。
<span style="font-family:KaiTi_GB2312;">//假设參数是空白区域则为true。否则为false bool space(char c) { return isspace(c); } //假设參数是空白区域则为false。否则为true bool not_space(char c) { return !isspace(c); } vector<string> split(const string& str) { typedef string::const_interator iter; vector<string> ret; iter != 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; }</span></span>
补充:
<span style="font-family:KaiTi_GB2312;">// lesson6.2.cpp : 定义控制台应用程序的入口点。 //功能:推断回文 //2014.5.22 #include "stdafx.h" #include <algorithm> #include <cctype> #include <iostream> #include <string> using namespace std; bool is_palindrome(const string& s) { return equal(s.begin(), s.end(), s.rbegin()); } int _tmain(int argc, _TCHAR* argv[]) { string s; while (cin >> s) { if (is_palindrome(s)) cout << s << " is a palindrome" << endl; else cout << s << " is not a palindrome" << endl; } return 0; }</span></span>
执行结果:
<span style="font-family:KaiTi_GB2312;">// lesson6_1.cpp : 定义控制台应用程序的入口点。 //功能:查找URL //时间:2014.5.22 #include "stdafx.h" #include <algorithm> #include <cctype> #include <iostream> #include <string> #include <vector> #include "urls.h" using namespace std; int _tmain(int argc, _TCHAR* argv[]) { string s; while (getline(cin,s)) { vector<string> v = find_urls(s); for(vector<string>::const_iterator i = v.begin(); i != v.end(); ++i) cout << *i << endl; } return 0; } </span></span>
urls头文件:
<span style="font-family:KaiTi_GB2312;">#ifndef GUARD_urls_h #define GUARD_urls_h #include <vector> #include <string> std::vector<std::string> find_urls(const std::string& s); #endif</span></span>
urls源文件:
<span style="font-family:KaiTi_GB2312;">#include <algorithm> #include <cctype> #include <string> #include <vector> #include "urls.h" using std::find; using std::find_if; #ifndef _MSC_VER using std::isalnum; using std::isalpha; using std::isdigit; #endif using std::search; using std::string; using std::vector; bool not_url_char(char); string::const_iterator url_end(string::const_iterator, string::const_iterator); string::const_iterator url_beg(string::const_iterator, string::const_iterator); 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; } //调用url_end目的是为了找出这个URL的结尾 string::const_iterator url_end(string::const_iterator b, string::const_iterator e) { return find_if(b, e, not_url_char); } //编写这个not_url_char的谓词 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()); //补充:isalnum函数是检验它的參数是否是一个字母数字字符(一个字母或者一个数字) } //负责识别是否有一个有效的URL,我们必须保证在://分隔符之前有一个或多个的字母。并且在它的后面至少有一个字符。 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; while ((i = search(i, e, sep.begin(), sep.end())) != e) { //确保切割符不是本行中唯一的一个符号 if (i != b && i + sep.size() != e) { // `beg标记协议名称的开关 iter beg = i; while (beg != b && isalpha(beg[-1])) //isalpha 推断不是字母 --beg; // 在分隔符前面以及后面至少有一个字符吗? if (beg != i && !not_url_char(i[sep.size()])) return beg; } //我们找到的分隔符不是一个URL的一部分 if(i != e) i += sep.size(); } return e; }</span></span>
执行结果:
<span style="font-family:KaiTi_GB2312;">// lesson6_3.cpp : 定义控制台应用程序的入口点。 //功能:计算成绩 //时间:2014.5.22 #include "stdafx.h" #include <vector> #include <iostream> #include "analysis.h" #include "Student_info.h" using namespace std; int _tmain(int argc, _TCHAR* 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 student did all the homework!" << endl; return 1; } if(didnt.empty()) { cout << "Every student did all the homework!" << endl; return 1; } //进行分析 write_analysis(cout, "median", median_analysis, did, didnt); write_analysis(cout, "average", average_analysis, did, didnt); write_analysis(cout, "median of homework turned in", optimistic_median_analysis, did, didnt); return 0; }</span></span>
<span style="font-family:KaiTi_GB2312;">#include <algorithm> #include "Student_info.h" using namespace std; //函数的目的就是查找储存在里面的全部值中是否有为0的 bool did_all_hw(const Student_info& s) { return((find(s.homework.begin(), s.homework.end(), 0)) == s.homework.end()); }</span></span>
不同的分析函数:
<span style="font-family:KaiTi_GB2312;">//功能:分析 //时间:2014.5.22 #include <slgorithm> #include <iostream> #include <iterator> #include <numeric> #include <stdexcept> #include <vector> #include "Student_info.h" #include "grade.h" #include "median.h" using namespace std; //建立一个辅助函数在grade内运行try语句而且处理异常 double grade_aux(const Student_info& s) { try { return grade(s); } catch(domain_error) { return grade(s.midterm, s.final, 0) } } //median_analysis double median_analysis(const vector<Student_info>& students) { vector<double> grades; transform(students.begin(), students.end(),back_inserter(grades), grade_aux); 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; } //计算家庭作业的平均成绩 double average(const vector<double>& v) { return accumulate(v.begin(), v.end(), 0.0) / v.size(); //这里一定要注意用0.0这样求出的值才不会丢了小数点部分 } //计算总成绩 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); } //上交家庭作业的中值,s.homework的非零元素的中值,假设没有这种元素存在的话。则为0 double optimistic_median(const Student_info& s) { vector<double> nonzero; 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)); } //optimistic_median_analysis 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); } </span></span>
<span style="font-family:KaiTi_GB2312;">#include <algorithm> #include <iterator> #include <vector> #include "Student_info.h" #include "grade.h" using namespace std; vector<Student_info> extract_fails(vector<Student_info>& students) { vector<Student_info> fail; remove_copy_if(students.begin(), students.end(),back_inserter(fail),pgrade); students.erase(remove_if(students.begin(),students.end(), fgrade), students.end()); return fail; }</span></span>
这里计算了两次成绩。所以须要改进
<span style="font-family:KaiTi_GB2312;">#include <algorithm> #include <vector> #include "Student_info.h" #include "grade.h" using std::stable_partition; using std::vector; vector<Student_info> extract_fails(vector<Student_info>& students) { vector<Student_info>::iterator iter = stable_partition(students.begin(), students.end(), pgrade); vector<Student_info> fail(iter, students.end()); students.erase(iter, students.end()); return fail; }</span></span>程序分析:
返回一个迭代器,这个迭代器指示了第一个令谓词为假的元素;
<span style="font-family:KaiTi_GB2312;">vector<int> u(10,100); vector<int> v; copy(u.begin(), u.end(), v.begin());</span>编写一个包括这个片段的程序并编译以及执行这个程序。
<span style="font-family:KaiTi_GB2312;">// lesson6_5_1.cpp : 定义控制台应用程序的入口点。//改进上面方法:利用迭代适配器,循环 //时间:2014.5.24 #include "stdafx.h" #include <algorithm> #include <iterator> #include <vector> using namespace std; int _tmain(int argc, _TCHAR* argv[]) { vector<int> u(10,100); vector<int> v; copy(u.begin(),u.end(),inserter(v,v.begin())); return 0; }</span>
方法二:
<span style="font-family:KaiTi_GB2312;">// lesson6_5_2.cpp : 定义控制台应用程序的入口点。 //改进:使用最初的循环来做 //时间:2014.5.24 #include "stdafx.h" #include <algorithm> #include <vector> using namespace std; int _tmain(int argc, _TCHAR* argv[]) { vector<int> u(10, 100); vector<int> v; for(vector<int>::const_iterator it = u.begin(); it != u.end(); ++it) v.push_back(*it); return 0; } </span>
程序说明:vector<int> u(10,100)定义了一个vector u,该vector中存有10个100。将u中的元素通过copy函数所有拷贝到v。
<span style="font-family:KaiTi_GB2312;">// lesson6_6.cpp : 定义控制台应用程序的入口点。 //功能:计算成绩的分析程序的一部分功能是读入学生记录并对其进行分类。这一部分程序依赖于学生是否做了所有的家庭作业,这个问题和extract_fails中所须要解决的相似 //时间:2014.5.24 #include "stdafx.h" #include <vector> #include <iostream> #include "analysis.h" #include "Student_info.h" using namespace std; //分类问题 vector<Student_info> extract_didnt(vector<Student_info>& input) { vector<Student_info>::iterator iter = stable_partition(input.begin(),input.end(),did_all_hw); vector<Student_info> output(iter,input.end()); input.erase(iter, input.end()); return output; } int _tmain(int argc, _TCHAR* argv[]) { // students who did and didn't do all their homework vector<Student_info> did; // read the student records and partition them Student_info student; while (read(cin, student)) did.push_back(student); vector<Student_info> didnt = extract_didnt(did); // verify that the analyses will show us something if (did.empty()) { cout << "No student did all the homework!" << endl; return 1; } if (didnt.empty()) { cout << "Every student did all the homework!" << endl; return 1; } // do the analyses write_analysis(cout, "median", median_analysis, did, didnt); write_analysis(cout, "average", average_analysis, did, didnt); write_analysis(cout, "median of homework turned in", optimistic_median_analysis, did, didnt); return 0; return 0; } </span>
程序说明:这里须要注意的就是stable_partition.
<span style="font-family:KaiTi_GB2312;">// lesson6_7.cpp : 定义控制台应用程序的入口点。//功能:编写一个函数。用这个函数来依照你自己的选择准则来对学生进行分类,使用它来取代extract_fails程序从而对它进行測试 //时间:2014.5.24 #include "stdafx.h" #include <algorithm> #include <vector> #include <iostream> #include <string> #include "6-7-classify.h" #include "Student_info.h" #include "grade.h" using namespace std; int _tmain(int argc, _TCHAR* argv[]) { vector<Student_info> vs; Student_info s; string::size_type maxlen = 0; while(read(cin,s)) { maxlen = max(maxlen, s.name.size()); vs.push_back(s); } sort(vs.begin(), vs.end(),compare); vector<Student_info> fails = classify(vs, pgrade); for(int i = 0; i < fails.size(); ++i) cout << fails[i].name << " " << grade(fails[i]) << endl; return 0; } </span>
分类函数:
<span style="font-family:KaiTi_GB2312;">#include <algorithm> #include "6-7-classify.h" using namespace std; //这就是依照自己的准则来分类 vector<Student_info> classify(vector<Student_info>& input, bool criteria(const Student_info&)) { ector<Student_info>::iterator iter = stable_partition(input.begin(), input.end(), criteria); vector<Student_info> output(iter, input.end()); input.erase(iter, input.end()); return output; }</span>
11、在lesson6_7中继续编写一个函数在程序中用它来分析学生的成绩
<span style="font-family:KaiTi_GB2312;">// lesson6_8.cpp : 定义控制台应用程序的入口点。//功能:在lesson6_7中继续编写一个函数在程序中用它来分析学生的成绩 #include "stdafx.h" #include <vector> #include <iostream> #include "6-8-classify.h" #include "analysis.h" #include "Student_info.h" using namespace std; int _tmain(int argc, _TCHAR* argv[]) { // students who did and didn't do all their homework vector<Student_info> did; // read the student records and partition them Student_info student; while (read(cin, student)) did.push_back(student); vector<Student_info> didnt = classify(did, did_all_hw);//这里是我们的两点地方 // verify that the analyses will show us something if (did.empty()) { cout << "No student did all the homework!" << endl; return 1; } if (didnt.empty()) { cout << "Every student did all the homework!" << endl; return 1; } // do the analyses write_analysis(cout, "median", median_analysis, did, didnt); write_analysis(cout, "average", average_analysis, did, didnt); write_analysis(cout, "median of homework turned in",optimistic_median_analysis, did, didnt); return 0; } </span>
12、使用一个库算法连接一个vector<string>对象中的全部元素
<span style="font-family:KaiTi_GB2312;">// lesson6_9.cpp : 定义控制台应用程序的入口点。 //功能:使用一个库算法连接一个vector<string>对象中的全部元素 //时间:2014.5.24 #include "stdafx.h" #include <vector> #include <string> #include <iostream> #include <iterator> #include <numeric> using namespace std; int _tmain(int argc, _TCHAR* argv[]) { cout << "Please enter some words: "; vector<string> v; string s; while(cin >> s) v.push_back(s); string sum = accumulate(v.begin(),v.end(),string("the string is:")); cout << sum << endl; return 0; } </span>
执行结果: