C++自学精简教程 目录(必读)
GPA概念回顾
平均学分绩点GPA(Grade Point Average)是对一个学生大学学习成绩的综合的衡量指标。
在前面的文章 本科生学分绩点GPA计算 中,我们知道了什么是平均学分绩点GPA,以及如何计算它。
基于GPA给学生排名
现在我们使用GPA数值作为考研名额的评判标准。
按照GPA数值从高到低,取3个名额作为保研名额。
题目描述
已知,某专业有10名同学,这10名同学的信息如下:
每一行记录表示一个学生的信息:学号, {10门课的成绩}, {10门课对应的学分}, "姓名"
学号, {10门课的成绩}, {10门课对应的学分}, "姓名"
111, { 88, 86, 87, 82, 82, 86, 83, 86, 80, 89 }, { 3, 3, 1, 1, 2, 1, 3, 2, 3, 3 } , "杜特尔特"
112, { 92, 80, 81, 75, 93, 80, 81, 89, 84, 85 }, { 3, 2, 3, 1, 2, 2, 2, 1, 1, 1 } , "文在寅"
113, { 88, 92, 93, 86, 84, 81, 81, 80, 81, 89 }, { 3, 2, 1, 2, 1, 3, 3, 3, 2, 3 } , "佐科"
114, { 94, 81, 89, 89, 80, 71, 88, 89, 89, 88 }, { 1, 3, 3, 2, 1, 1, 3, 1, 3, 3 } , "莱希"
115, { 83, 85, 84, 82, 63, 81, 83, 64, 81, 83 }, { 1, 2, 1, 3, 1, 3, 1, 1, 1, 2 } , "雅各布"
116, { 90, 81, 84, 91, 85, 88, 84, 72, 94, 87 }, { 2, 2, 2, 1, 2, 2, 1, 1, 2, 3 } , "卢卡申科"
117, { 89, 81, 86, 88, 81, 91, 84, 75, 90, 88 }, { 2, 2, 2, 2, 1, 3, 3, 2, 2, 3 } , "马克龙"
118, { 82, 80, 82, 94, 87, 80, 94, 80, 71, 92 }, { 1, 2, 3, 3, 1, 2, 3, 3, 2, 1 } , "萨科奇"
119, { 89, 91, 80, 90, 85, 87, 87, 94, 81, 70 }, { 2, 3, 3, 2, 3, 2, 2, 3, 1, 3 } , "默克尔"
120, { 88, 95, 84, 89, 92, 79, 80, 96, 83, 80 }, { 3, 4, 1, 3, 3, 2, 2, 4, 3, 3 } , "金正恩"
根据本科生学分绩点GPA计算 文章中的内容,我们就可以计算出每个学生的GPA。
现在需要取GPA从高到低排序,前三名作为保研名额。
请你求出哪三个人会被保研。
分析设计
一、整体流程
首先,我们需要求出每个学生的GPA。
而要求GPA,就需要拿到学生的数据。
学生的数据如何存放,决定了我们计算的是否方便。
我们的整体流程大致如下:
(1)合理的组织学生的数据,放到合适的容器里
(2)计算每个学生的GPA
(3)对学生的GPA排序
(4)根据排序结果输出哪些学生可以保研
二、具体设计
1 学生类
首先,我们需要一个学生类来描述和保存一个学生的数据。
根据题目中给出的数据格式,我们可以得出学生类应该像下面这样:
struct Student //学生类
{
int id;//学号
vector<int> score_list;//修的所有课程的成绩列表
vector<int> credit_hour_list;//修的所有课程对应的学分列表
double GPA;//注意GPA应该是浮点数,不能是整数
string name;//姓名
};
2 GPA计算
现在,我们把每个学生的考试成绩和各门课的学分都放在了学生类的内部存储。
我们给学生类增加了两个成员函数:
double get_GPA(void) const { return GPA; }
void set_GPA(void);
3 学生数据的存放
我们把全部学生信息放到一个容器container1里。
后面我们对每个学生计算出对应的GPA,也存在学生信息里。
同时,我们需要从这个容器里查询某个学生的GPA数值,所以这个容器要求可以根据学生的ID来查询学生的信息。
所以,container1应该是:
map<id, student> student_map;
这个时候我们需要,遍历容器student_map ,把GPA数据拿出来,同时保留GPA和学生的对应关系。
这样我们就可以对GPA排序,同时知道GPA和学生的对应关系。
所以我们需要另一个容器container2。
这个容器可以支持用GPA作为key排序,这让我们再次想到了map。
也就是大致像这样:
map<GPA, student> gpa_order;
而map自动会对key进行排序,只需要不断的往里面插入元素即可。
所以,我们得到的container2像下面这样:
最后是输出谁被保研了。
此时只需要按照顺序遍历container2,就会得到GPA从高到低的顺序。
container2提供顺序,container1提供学生信息,这样就可以对学生按照GPA排序了:
4 程序整体结构
解决了数据结构,剩下的就是整体流程分析的思路实现完整的程序了。
程序框架见后面的启动代码。
启动代码
#include <iostream>
#include <vector> //存放学生的课程和学分
#include <string> //存放学生的名字
#include <iomanip> //格式控制:小数部分2位小数
#include <map> //存放学生数据,排序数据
using namespace std;
struct Student
{
double get_GPA(void) const { return GPA; }
void set_GPA(void);//计算学生的GPA数值,存到学生的GPA成员变量中
int id;//学号
vector<int> score_list;//修的所有课程的成绩列表
vector<int> credit_hour_list;//修的所有课程对应的学分列表
double GPA;
string name;//姓名
};
void Student::set_GPA(void)
{
//累加课程学分绩点=课程学分绩点1+课程学分绩点2+...+课程学分绩点n
double total_credit_hour_point = 0;
for (int i = 0; i < score_list.size(); i++)
{
//课程绩点=课程成绩/10 -5
double grade_point = score_list[i] / 10.0 - 5;//注意这里整数通过除以浮点数结果转换成了浮点数
//课程学分绩点
double credit_hour_point = credit_hour_list[i] * grade_point;
//累加课程学分绩点
total_credit_hour_point += credit_hour_point;
}
//平均学分绩点
//各门课学分之和sum_credit_hour
int sum_credit_hour = 0;
for (int i = 0; i < score_list.size(); i++)
{
sum_credit_hour += credit_hour_list[i];//累加
}
//平均学分绩点= 累加课程学分绩点/各门课学分之和
GPA = total_credit_hour_point / sum_credit_hour;
}
void init_student_data(map<int, Student>& student_map)
{
student_map[111] = { 111, { 88, 86, 87, 82, 82, 86, 83, 86, 80, 89 }, { 3, 3, 1, 1, 2, 1, 3, 2, 3, 3 } , 0.0, "杜特尔特" };
student_map[112] = { 112, { 92, 80, 81, 75, 93, 80, 81, 89, 84, 85 }, { 3, 2, 3, 1, 2, 2, 2, 1, 1, 1 } , 0.0, "文在寅" };
student_map[113] = { 113, { 88, 92, 93, 86, 84, 81, 81, 80, 81, 89 }, { 3, 2, 1, 2, 1, 3, 3, 3, 2, 3 } , 0.0, "佐科" };
student_map[114] = { 114, { 94, 81, 89, 89, 80, 71, 88, 89, 89, 88 }, { 1, 3, 3, 2, 1, 1, 3, 1, 3, 3 } , 0.0, "莱希" };
student_map[115] = { 115, { 83, 85, 84, 82, 63, 81, 83, 64, 81, 83 }, { 1, 2, 1, 3, 1, 3, 1, 1, 1, 2 } , 0.0, "雅各布" };
student_map[116] = { 116, { 90, 81, 84, 91, 85, 88, 84, 72, 94, 87 }, { 2, 2, 2, 1, 2, 2, 1, 1, 2, 3 } , 0.0, "卢卡申科" };
student_map[117] = { 117, { 89, 81, 86, 88, 81, 91, 84, 75, 90, 88 }, { 2, 2, 2, 2, 1, 3, 3, 2, 2, 3 } , 0.0, "马克龙" };
student_map[118] = { 118, { 82, 80, 82, 94, 87, 80, 94, 80, 71, 92 }, { 1, 2, 3, 3, 1, 2, 3, 3, 2, 1 } , 0.0, "萨科奇" };
student_map[119] = { 119, { 89, 91, 80, 90, 85, 87, 87, 94, 81, 70 }, { 2, 3, 3, 2, 3, 2, 2, 3, 1, 3 } , 0.0, "默克尔" };
student_map[120] = { 120, { 88, 95, 84, 89, 92, 79, 80, 96, 83, 80 }, { 3, 4, 1, 3, 3, 2, 2, 4, 3, 3 } , 0.0, "金正恩" };
}
void set_student_gpa(map<int, Student>& student_map, map<double, int>& gpa_order)
{
for (auto& student : student_map)
{
student.second.set_GPA();
double gpa = student.second.get_GPA();
//(1) your code
}
}
void print_student_research_quota(map<double, int>& gpa_order, map<int, Student>& student_map)
{
int pass_count = 3;
int i = 0;
//从后向前迭代容器:逆序迭代。因为map默认是从小到大排序,最小的元素放在最开始的位置
for (auto itr = gpa_order.rbegin(); itr != gpa_order.rend(); ++itr)
{
auto& student = student_map[itr->second];
cout << "GPA="
//fixed使用小数计数法(而不是科学计数法)显示浮点数
<< fixed
//setprecision(2) 小数部分保留2位,最后一位四舍五入
<< setprecision(2) << student.get_GPA()
<< ", id=" << student.id;
if (i < pass_count)
{
cout << ", 保研";
}
else
{
cout << ", 不保";
}
//(2) your code
cout << ", name=" << student.name << endl;
}
}
int main()
{
map<int, Student> student_map;
init_student_data(student_map);
map<double, int> gpa_order;
//计算学生的GPA,并存放到gpa_order里
set_student_gpa(student_map, gpa_order);
//输出哪些学生被保研了,哪些没有
print_student_research_quota(gpa_order, student_map);
return 0;
}
正确结果
答案在此
C++自学精简教程 全部答案