1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
|
#include <algorithm>
#include <iomanip>
#include <iostream>
#include <ios>
#include <string>
#include <vector>
#include <stdexcept>
using namespace std;
/*
* Student_info is a type which has four data members: name, midterm, final and homework.
* because Student_info is a type we can define objects of that this type each of which
* will contain an instance of these four data members, ie: vector<Student_info> students;
* can be created s/t one can call its data members, ie: students.grade, students.midterm,
* students.name, etc...
*/
struct Student_info
{
string name;
double midterm, final;
vector<double> homework;
};
/*
* The compare function delegates the work of comparing Student_info/s to the string class,
* which provides a < operator for comparing strings. That operator compares strings by
* applying normal dictionary ordering. That is, it considers the left-hand operand to be
* less than the right-hand operand if it is alphabetically ahead of the right-hand operand.
*/
bool compare(const Student_info& x, const Student_info& y)
{
return x.name < y.name;
}
/*
* The median function begins by diving size by 2 in order to locate the middle of the vector.
* If the number of elements is even, this division is exact. If the number is odd, then the
* result is the next lower integer. If it is even, the median is the average of the two
* elements closest to the middle. Otherwise, there is an element in the middle, the value
* of which is the median.
*/
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];
}
// Compute a students overall grade given a midterm, final exam and homework grade.
double grade(double midterm, double final, double homework)
{
return 0.2 * midterm + 0.4 * final + 0.4 * homework;
}
/*
* Compute a student's overall grade from midterm and final exam grades and a vector
* of homework grades. This function does not copy its argument because median()
* already does that for us.
*/
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));
}
// Determine a students overall grade given a midterm, final exam and homework grade.
double grade(const Student_info& s)
{
return grade(s.midterm, s.final, s.homework);
}
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;
}
istream& read(istream& is, Student_info& s)
{
is >> s.name >> s.midterm >> s.final;
read_hw(is, s.homework);
return is;
}
int main()
{
vector<Student_info> students;
Student_info record;
string::size_type maxlen = 0;
while(read(cin, record))
{
maxlen = max(maxlen, record.name.size());
students.push_back(record);
}
sort(students.begin(), students.end(), compare);
for(vector<Student_info>::size_type i = 0; i != students.size(); ++i)
{
cout << students[i].name << string(maxlen + 1 - students[i].name.size(), ' ');
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;
}
|