实验内容:
创建一个Score类,完成一下功能:
- 连续输入多个学生的float成绩(成绩=科目A成绩+科目B成绩+科目C成绩);
- 学生数目可以由用户自定义(默认为2个,最多为100个);
- 显示每位同学的每科成绩和平均分;
- 显示每门科目的平均成绩;
- 对每门成绩进行排序并由高到低显示;
- 对整个文件进行打包
首先是定义一个Score类,其中包括构造函数,析构函数与一些其他一般的成员函数,构造函数的作用主要是用来对对象进行初始化。例如在此次上机中 Score x;这是对对象初始化,这时x没有给出后面的参数,就为默认的学生数目2人。可以在类中定义了两个构造函数,第1个构造函数没有参数,在函数体中对私有的数据成员赋以固定的值。第2构造函数有3个参数,在函数体中分别把参数值赋给数据成员。这两个构造函数同名,是两个重载的构造函数。类的代码定义如下:
class Score {
public:
Score() {
num = 2;
cout << "此时默认学生数为2人!" << endl;
}
Score(int num1) {
num = num1;
cout << "此时需输入" << num << "个学生" << endl;
}
~Score() {
cout << "Score destruction called!" << endl;
}
void InputStu_Infor();
void ShowStu();
void ShowClass_avg();
void ShowRank();
private:
int num; //输入学生数
string name[100]; //学生名字
float ChengJi[3][100];
};
类中分为了公有成员和私有成员,公有成员除了构造函数和析构函数之外,还在类内声明了输入学生信息,显示学生信息,显示课程的平均函数,显示成绩的排序这些函数。而输入的信息存放在私有成员中,外部无法直接访问,只能通过成员函数进行访问。
在类中声明的函数,可在类外进行定义,但需要加上作用域运算符(::),在类外定义的函数如下所示。
void Score::InputStu_Infor() {
for (int i = 0; i < num; i++) {
cout << "请输入学生姓名:" << endl;
cin >> name[i];
cout << "请输入科目A的成绩:" << endl;
cin >> ChengJi[0][i];
cout << "请输入科目B的成绩:" << endl;
cin >> ChengJi[1][i];
cout << "请输入科目C的成绩:" << endl;
cin >> ChengJi[2][i];
}
}
void Score::ShowStu() {
int i ;
float Stu_avg = 0;
for (i = 0; i < num; i++) {
cout << "姓名:" << name[i] << " 科目A成绩:" << ChengJi[0][i] << " 科目B成绩:" << ChengJi[1][i] << " 科目C成绩:" << ChengJi[2][i] << endl;
Stu_avg = ChengJi[0][i] / 3 + ChengJi[1][i] / 3 + ChengJi[2][i] / 3;
cout << "姓名:" << name[i] << " 平均成绩:" << Stu_avg << endl;
}
}
void Score::ShowClass_avg() {
float ClassA_avg = 0;
float ClassB_avg = 0;
float ClassC_avg = 0;
int i;
for (i = 0; i < num; i++) {
ClassA_avg += ChengJi[0][i] / num;
ClassB_avg += ChengJi[1][i] / num;
ClassC_avg += ChengJi[2][i] / num;
}
cout << "课程名称:A" << "平均成绩:" << ClassA_avg << endl;
cout << "课程名称:B" << "平均成绩:" << ClassB_avg << endl;
cout << "课程名称:C" << "平均成绩:" << ClassC_avg << endl;
}
void Score::ShowRank() {
float temp;
for (int j = 0; j < 3; j++) {
for (int i = 0; i < num; i++) {
if (ChengJi[i][j] < ChengJi[i][j + 1]) {
temp = ChengJi[i][j];
ChengJi[i][j] = ChengJi[i][j + 1];
ChengJi[i][j + 1] = temp;
}
}
}
cout << "科目A的成绩排序为:";
for (int i = 0; i < num; i++) {
cout << ChengJi[0][i] << " ";
}
cout << "\n科目B的成绩排序为:";
for (int i = 0; i < num; i++) {
cout << ChengJi[1][i] << " ";
}
cout << "\n科目C的成绩排序为:";
for (int i = 0; i < num; i++) {
cout << ChengJi[2][i] << " ";
}
cout << endl;
}
通过使用函数,能够完成显示每门课的平均成绩,与每位同学的平均分和对每门成绩进行排序并由高到低显示。主函数如下
int main() {
Score x;
x.InputStu_Infor();
x.ShowStu();
x.ShowClass_avg();
x.ShowRank();
return 0;
}
程序执行如下图所示:
排序方法:
1、冒泡排序
最简单的一种排序算法。假设长度为n的数组arr,要按照从小到大排序。则冒泡排序的具体过程可以描述为:首先从数组的第一个元素开始到数组最后一个元素为止,对数组中相邻的两个元素进行比较,如果位于数组左端的元素大于数组右端的元素,则交换这两个元素在数组中的位置,此时数组最右端的元素即为该数组中所有元素的最大值。接着对该数组剩下的n-1个元素进行冒泡排序,直到整个数组有序排列。
float temp;
for (int j = 0; j < 3; j++) {
for (int i = 0; i < num; i++) {
if (ChengJi[i][j] < ChengJi[i][j + 1]) {
temp = ChengJi[i][j];
ChengJi[i][j] = ChengJi[i][j + 1];
ChengJi[i][j + 1] = temp;
}
}
}
2、选择排序
首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。重复第二步,直到所有元素均排序完毕。
for (int i = 0; i < arr.size() - 1; i++) {
int min = i;
for (int j = i + 1; j < arr.size(); j++)
if (arr[j] < arr[min])
min = j;
std::swap(arr[i], arr[min]);
}
3、快速排序
快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序 n 个项目要 Ο(nlogn) 次比较。在最坏状况下则需要 Ο(n2) 次比较,但这种状况并不常见。事实上,快速排序通常明显比其他 Ο(nlogn) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来。快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists)。快速排序又是一种分而治之思想在排序算法上的典型应用。本质上来看,快速排序应该算是在冒泡排序基础上的递归分治法。
//严蔚敏《数据结构》标准分割函数
Paritition1(int A[], int low, int high) {
int pivot = A[low];
while (low < high) {
while (low < high && A[high] >= pivot) {
--high;
}
A[low] = A[high];
while (low < high && A[low] <= pivot) {
++low;
}
A[high] = A[low];
}
A[low] = pivot;
return low;
}
void QuickSort(int A[], int low, int high) //快排母函数
{
if (low < high) {
int pivot = Paritition1(A, low, high);
QuickSort(A, low, pivot - 1);
QuickSort(A, pivot + 1, high);
}
}
实验总结:
本次实验难度有一些,在实验之前需要确定程序实现的功能,并组织好需要使用几个函数来完成这些功能。对数据的处理也要思考好将数据放入哪,并以什么形式进行存放。在这些都清楚的情况下,对程序进行编写,会变得快捷一些,不会因为自己之前还没有想好该怎么做而导致写程序的时候逻辑不顺,该有的数据没有。在实现功能的时候,如若碰到许多方法,可以选择较为简便的进行使用。
本次实验所遇困难:
1、在编写程序时,科目A,科目B,科目C的成绩放入不同的成绩数组,这样导致了后面对成绩进行排序与求平均值造成了程序有些冗余,因此之后对数据的存放需要做到的是,一样类型的数据,最好存入在相同的单元中,如一个二维的数组。
2、对类的定义可以放在头文件中进行定义。但头文件中如果只有一个类的定义与包含的头文件,编译时会有报错的情况出现。如下图所示:
而在头文件中,有命名空间 using namespace std; 即能够正常的运行程序。效果如下图所示: