Accelerated C++学习笔记5—<组织程序和数据>
第4章 组织程序和数据
<span style="font-family:KaiTi_GB2312;">//根据学生的期中考试、期末考试、家庭作业成绩来计算总成绩 double grade(double midterm, double final, double homework) { return 0.2 * midterm + 0.4 * final + 0.4 * homework; }</span>
2)查找中值
<span style="font-family:KaiTi_GB2312;">/计算一个vector<double>类型的变量的中值 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]; }</span>
3)重新制定计算成绩的策略
<span style="font-family:KaiTi_GB2312;">//根据期中、期末考试成绩和保存家庭作业的向量来计算学生的总成绩 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)); }</span>
程序说明:
<span style="font-family:KaiTi_GB2312;">//从输入流中将家庭作业的成绩读入一个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(); } return in; }</span>
程序说明:
<span style="font-family:KaiTi_GB2312;">// lesson4_1.cpp : 定义控制台应用程序的入口点。 //功能:使用函数来计算学生的成绩 //时间:2014.5.12 #include "stdafx.h" #include <algorithm> #include <iomanip> //#include <ios> #include <stdexcept> #include <iostream> #include <string> #include <vector> using std::cin; using std::cout; using std::domain_error; using std::endl; using std::istream; using std::ostream; using std::setprecision; using std::sort; using std::streamsize; using std::string; using std::vector; //根据学生的期中考试、期末考试、家庭作业成绩来计算总成绩 double grade(double midterm, double final, double homework) { return 0.2 * midterm + 0.4 * final + 0.4 * homework; } //计算一个vector<double>类型的变量的中值 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]; } //根据期中、期末考试成绩和保存家庭作业的向量来计算学生的总成绩 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)); } //从输入流中将家庭作业的成绩读入一个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(); } return in; } int _tmain(int argc, _TCHAR* argv[]) { //请求并读入学生姓名 cout << "Please enter your first name: "; string name; cin >> name; cout << "Hello, " << name << "!" << endl; //请求并读入期中和期末考试的成绩 cout << "Please enter your midterm and final exam grades: "; double midterm, final; cin >> midterm >> final; //请求用户输入家庭作业成绩 cout << "Enter all your homework grades, " "followed by end-of-file: "; vector<double> homework; //读入家庭作业成绩 read_hw(cin, homework); //如果可以的话,计算生成总成绩 try { double final_grade = grade(midterm, final, homework); streamsize prec = cout.precision(); cout << "Your final grade is " << setprecision(3) << final_grade << setprecision(prec) << endl; } catch (domain_error) { cout << endl << "You must enter your grades. " << "Please try again." << endl; return 1; } return 0; } </span>
运行结果:
<span style="font-family:KaiTi_GB2312;">struct Student_info { string name; double midterm, final; vector<double> homework; };//这里一定要注意分号是不可缺少的</span>
程序说明:
<span style="font-family:KaiTi_GB2312;">//需要读学生的姓名以及考试成绩 istream& read(istream& is, Student_info& s) { is >> s.name >> s.midterm >> s.final; read_hw(is, s.homework);//读入并储存学生的所有家庭作业成绩 return is; }</span>
程序说明:
<span style="font-family:KaiTi_GB2312;">double grade(const Student_info& s) { return grade(s.midterm, s.fianl, s.homework); }</span>
<span style="font-family:KaiTi_GB2312;">sort(student.begin(), student.end());</span>
因为sort试图去比较两个这样的对象的话,编译器会报错。
<span style="font-family:KaiTi_GB2312;">// 按字母顺序排列学生记录 bool compare(const Student_info& x, const Studnt_info& y) { return x.name < y.name; } sort(students.begin(), students.end(), compare);</span>
这里编写的比较函数仅仅是对名字进行比较。
<span style="font-family:KaiTi_GB2312;">int _tmain(int argc, _TCHAR* argv[]) { vector<Student_info> students; Student_info record; string::size_type maxlen = 0; //最长的姓名的长度 //读入并存储所有学生的数据 //不变式 // students 包含了所有的学生的记录 // max包含了students中最长的姓名 while (read(cin, record)) //找出最长的姓名的长度 { maxlen = max(maxlen, record.name.size()); students.push_back(record); } // 按字母顺序排列学生记录 sort(students.begin(), students.end(), compare); //输出姓名和成绩 for (std::vector<Student_info>::size_type i = 0; j != students.size(); ++i) { //输出姓名,把姓名填充至maxlen + 1 个字符长度 cout << setw(maxlen+1) << students[i].name; //计算并输出成绩 try { double final_grade = grade(students[i]); streamsize prec = cout.precision(); cout << setprecision(3) << final_grade << setprecision(prec); } catch(domain_error e) { cout << e.what(); } cout << endl; } return 0; }</span>
程序说明:
<span style="font-family:KaiTi_GB2312;">//median函数的源文件 #include "stdafx.h" #include <algorithm> //获取sort声明 #include <stdexcept> //获取domain_error的声明 #include <vector> //获取vector的声明 using namespace std; //计算一个vector<double>类型的对象的中值 { 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]; }</span>
程序说明:我们需要把median函数放如一个名为median.cpp,或者median.C或者median.c文件中。
<span style="font-family:KaiTi_GB2312;">//使用median函数的一种较好的方法 #include "median.h" #include <vector> int main {……}</span>
程序说明:如果我们在#include指令中使用了一个双引号而不是尖括号来把头文件名称括起来,那么就表示,为了替代#include指令,我们要求编译器把与此名称对应的头文件中所有内容都复制到我们的程序中。
<span style="font-family:KaiTi_GB2312;">#ifndef GUARD_median_h #define GUARD_median_h #include <vector> double median(vector<double>); #endif</span>
程序说明
<span style="font-family:KaiTi_GB2312;">#ifndef GUARD_Student_info #define GUARD_Student_info //Student_info.h 头文件 #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(std::istream&, Student_info&); std::istream& read_hw(std::istream&, std::vector<double>&); #endif </span>
程序说明:注意这里我们在限定标准库的名称的时候所使用的是std::而不是using声明。
<span style="font-family:KaiTi_GB2312;">#include "Student_info.h" using std::istream; using std::vector; bool compare(const Student_info& x, const Student_info& y) { return x.name < y.name; } 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); //清除the stream 保证可以工作到下一个学生 in.clear(); } return in; }</span>
程序说明:源文件中使用using声明并没有问题,不像头文件,源文件对使用这些函数的程序没有影响。因此在源文件中使用using声明只不过是一个局部的决策罢了,不会影响到全局。
<span style="font-family:KaiTi_GB2312;">#ifndef GUARD_grade_h #define GUARD_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&); double grade(const Student_info&); #endif</span>
源文件:
<span style="font-family:KaiTi_GB2312;">#include <stdexcept> #include <vector> #include "grade.h" #include "median.h" #include "Student_info.h" using std::domain_error; using std::vector; //计算一个vector<double>类型的对象的中值 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]; } //根据期中、期末考试成绩和保存家庭作业的向量来计算学生的总成绩 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)); } //需要读学生的姓名以及考试成绩 istream& read(istream& is, Student_info& s) { is >> s.name >> s.midterm >> s.final; read_hw(is, s.homework);//读入并储存学生的所有家庭作业成绩 return is; }</span>
5、修正后的计算成绩的程序
<span style="font-family:KaiTi_GB2312;">// lesson4.2.cpp : 定义控制台应用程序的入口点。 //功能:修正后的计算成绩的程序 //时间:2014.5.12 #include "stdafx.h" #include <algorithm> #include <iomanip> #include <stdexcept> #include <string> #include <vector> #include "grade.h" #include "Student_info.h" using namespace std; int _tmain(int argc, _TCHAR* argv[]) { vector<Student_info> students; Student_info record; string::size_type maxlen = 0; //最长的姓名的长度 //读入并存储所有学生的数据 //不变式 // students 包含了所有的学生的记录 // max包含了students中最长的姓名 while (read(cin, record)) //找出最长的姓名的长度 { maxlen = max(maxlen, record.name.size()); students.push_back(record); } // 按字母顺序排列学生记录 sort(students.begin(), students.end(), compare); //输出姓名和成绩 for (std::vector<Student_info>::size_type i = 0; i != students.size(); ++i) { //输出姓名,把姓名填充至maxlen + 1 个字符长度 cout << setw(maxlen+1) << students[i].name; //计算并输出成绩 try { double final_grade = grade(students[i]); streamsize prec = cout.precision(); cout << setprecision(3) << final_grade << setprecision(prec); } catch(domain_error e) { cout << e.what(); } cout << endl; } return 0; } </span>
<span style="font-family:KaiTi_GB2312;">// lesson4_3.cpp : 定义控制台应用程序的入口点。 //功能:编写一个程序来计算从1-100的整数(int)值的平方。程序的输出分为两列;第一列是整数值。第二列是整数值的平方 //时间:2014.5.12 #include "stdafx.h" #include <cmath> #include <iomanip> //定义控制器setprecision 这个控制器可以让我们指明输出所包含的有效位数 #include <iostream> using namespace std; int _tmain(int argc, _TCHAR* argv[]) { for(int i = 1; i <= 100; ++i) { cout << setw(3) << i << setw(6) << i * i << endl; } return 0; } </span>运行结果:
程序说明:setw(n) 返回一个类型为streamsize的值,如果把这个函数用于输出流s,那么它的作用跟调用s.width(n)的一样。
<span style="font-family:KaiTi_GB2312;">// lesson4_4.cpp : 定义控制台应用程序的入口点。 //功能:让它更好的适应性,当i增长的时不需要修正setw的参数 //时间:2014.5.12 #include "stdafx.h" #include <cmath> #include <iomanip> #include <iostream> using namespace std; int get_width(double n) { return log10(n) + 1; } int _tmain(int argc, _TCHAR* argv[]) { double max = 100.0; for(int i = 1; i <= max; ++i) { cout << setw(get_width(max)) << i << setw(get_width(max * max) + 1) << i * i << endl; } return 0; } </span>
注意:VS2008中定义的那个get_width只能用float,否则报错。
<span style="font-family:KaiTi_GB2312;">// lesson4_5.cpp : 定义控制台应用程序的入口点。 //功能:编写一个函数来从输入流读单词,把读到的单词存储在一个向量中,利用这个函数编写一个程序来计算输入的单词的数目以及每一个单词所出现的次数。 //时间:2014.5.13 #include "stdafx.h" #include <algorithm> #include <iostream> #include <string> #include <vector> using namespace std; //从输入流中将单词读入到一个vector<string> istream& read_words(istream& in, vector<string>& words) { if(in) { //清除原先的内容 words.clear(); //读单词 string word; while (in >> word) words.push_back(word); //清除流以使输入动作对下一个单词有效 in.clear(); } return in; } int _tmain(int argc, _TCHAR* argv[]) { typedef vector<string>::size_type vec_sz; vector<string> words; read_words(cin, words); cout << "Num of words: " << words.size() << endl; sort(words.begin(), words.end()); string prev_word = ""; int count = 0; for(vec_sz i = 0;i < words.size(); ++i) { if (words[i] != prev_word) { if (prev_word != "") { cout << prev_word << " appeared " << count << "times" << endl; } prev_word = words[i]; count = 1; } else ++count; } cout << prev_word << " appeared " << count << "times" << endl; return 0; } </span>
运行结果:
这个语句的后面空白部分,都删除掉,免得有不可见的全角空格。可能是不小心按到空格键了。
9、编写一个程序来计算存储在一个vector<double>类型的向量中的数据的平均值<span style="font-family:KaiTi_GB2312;">// lesson4_7.cpp : 定义控制台应用程序的入口点。 //功能:编写一个程序来计算存储在一个vector<double>类型的向量中的数据的平均值 #include "stdafx.h" #include <iostream> #include <numeric> #include <vector> using namespace std; int _tmain(int argc, _TCHAR* argv[]) { vector<double> nums; double num; while (cin >> num) nums.push_back(num); cout << accumulate(nums.begin(), nums.end(), 0.0) / nums.size() << endl; //如果不要求存储在一个vector<double>类型的向量 /*int count = 0; double sum = 0; double x; //把数据读入变量x中 while (cin >> x) { ++count; sum += x; } cout << "The avg: " << sum / count << endl; */ return 0; } </span>
程序说明:本程序使用了accumulate函数
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。