一、实验内容 O创建一个Score类,完成以下功能: O连续输入多位学生的float成绩(成绩=科目A成绩+科目B成绩+科目C成绩) ; O学生数目可以由用户自定义(默认为2个,最多为100个) ; O显示每位同学的每科成绩和平均分; O显示每门科目的平均成绩; O对每门成绩进行排序并由高到低显示; O对整个文件进行打包。 二、程序代码 1. .cpp文件 这里首先声明了一个类source,包括构造函数,析构函数和一些具有一定功能的成员函数,成员变量,成员函数功能将在类的外部进行定义声明。第一个构造函数为无参函数,使用时,默认值为2,即在未声明学生数目时,默认的学生数目为2。第二个构造函数有参数,可通过改变参数来改变学生数目。
#include"shangji4.h"
class source {
public:
source()
{
num = 2;
cout << "默认的学生数目为:" << num << endl;
}
source(int num1)
{
num = num1;
cout << "实际的学生数目:" << num << endl;
}
~source()
{
cout << "source destruction called" << endl;
}
void inputsource();
void showsource();
void show_avg_chengji();
void show_chengji_order();
private:
int num;
string name[100];
float chengji[100][3];
};
进行类中函数的定义。类中函数的定义即可在类的内部声明时直接定义,也可在类的外部定义。该程序是在类声明中只给出成员函数的原型,而将成员函数的定义放在类的外部。这种成员函数定义的一般格式为:
返回值类型 类名 :: 成员函数名(参数表) { 函数体 } 在类外定义成员函数时,在类名和函数名之间应加上作用域运算符“::”,用于声明这个成员函数是哪个类的。 本段代码中,实现了连续输入多位学生的姓名和成绩,显示每位同学的每科成绩和平均分等全部功能。
void source::inputsource()
{
for (int i = 0; i < num; i++)
{
cout << "第" << i + 1 << "位学生姓名:" << endl;
cin >> name[i];
cout << "请输入科目A成绩:" << endl;
cin >> chengji[i][1];
cout << "请输入科目B成绩:" << endl;
cin >> chengji[i][2];
cout << "请输入科目C成绩:" << endl;
cin >> chengji[i][3];
}
}
void source::showsource()
{
for (int i = 0; i < num; i++)
{
cout << "学生姓名:" << name[i] << " 科目A成绩:" << chengji[i][1] << " 科目B成绩:" << chengji[i][2] << " 科目C成绩:" << chengji[i][3] << endl;
cout << name[i] << "的平均成绩:" << (chengji[i][1] + chengji[i][2] + chengji[i][3]) / 3 << endl;
}
}
void source::show_avg_chengji()
{
float avg_A = 0;
float avg_B = 0;
float avg_C = 0;
for (int i = 0; i < num; i++)
{
avg_A = chengji[i][1] + avg_A;
avg_B = chengji[i][2] + avg_B;
avg_C = chengji[i][3] + avg_C;
}
cout << "科目A平均成绩:" << avg_A / num << endl;
cout << "科目B平均成绩:" << avg_B / num << endl;
cout << "科目C平均成绩:" << avg_C / num << endl;
}
void source::show_chengji_order()
{
float transit_chengji;
string transit_name;
for (int k = 1; k < 4; k++)
{
for (int i = 0; i < (num - 1); i++)
{
if (chengji[i + 1][k] > chengji[i][k])
{
transit_chengji = chengji[i][k];
chengji[i][k] = chengji[i + 1][k];
chengji[i + 1][k] = transit_chengji;
transit_name = name[i];
name[i] = name[i + 1];
name[i + 1] = transit_name;
}
}
if (k == 1)
cout << "科目A的成绩排序:";
else if (k == 2)
cout << "科目B的成绩排序:";
else
cout << "科目C的成绩排序:";
for (int j = 0; j < num; j++)
{
cout << " " << name[j] << setw(3) << chengji[j][k];
}
cout << endl;
}
}
主函数中定义了类的对象 source x; 通过该对象访问类中的成员函数能够实现要求功能,此时默认的学生数目为2。当定义的对象为 source x(5);时 此时学生数目为5,即执行5个学生的成绩操作。
int main()
{
source x;
x.inputsource();
x.showsource();
x.show_avg_chengji();
x.show_chengji_order();
system("pause");
}
这次头文件中,与上次上机实验比较,新增了#include,#include头文件,以增加不同的功能。姓名为字符串形式,可定义为string name[100];并且使用了setw()函数,setw() 默认填充的内容为空格,当后面紧跟着的输出字段长度小于 n 的时候,在该字段前面用空格补齐,当输出字段长度大于 n 时,全部整体输出。
#include<iostream>
#include<string>
#include<iomanip>
using namespace std;
三、代码运行结果 默认值为2时: 当执行 int main() { source x(5); x.inputsource(); x.showsource(); x.show_avg_chengji(); x.show_chengji_order(); system(“pause”); } 时,结果为: 四、排序方法 1、sort函数: sort( ),括号里可以接受两个或三个参数。使用sort( )时需要添加头文件,这个英文单词的意思是“ 运算法则”。 接受两个参数时默认的排序方式是升序,添加第三个参数是为了实现降序。第一个参数是所要排序的数列的首地址,而第二个参数是该数列的最后一个数的地址加一。比如要对数组a[7]={5,7,9,10,8,2,3}排序,则是sort(a,a+7)。 参考程序:
#include<iostream>
#include<algorithm>
using namespace std;
int main() {
int a[10]= {9,6,3,8,5,2,7,4,1,0};
for(int i=0; i<10; i++)
cout<<a[i]<<" ";
cout<<endl;
sort(a,a+10);
for(int i=0; i<10; i++)
cout<<a[i]<<" ";
return 0;
}
运行结果:
9 6 3 8 5 2 7 4 1 0
0 1 2 3 4 5 6 7 8 9
2、冒泡排序 1.冒泡排序是最简单的排序方法,理解起来容易,步骤比较多。 2.冒泡排序的原理是:从左到右,相邻元素进行比较。每次比较一轮,就会找到序列中最大的一个或最小的一个。这个数就会从序列的最右边冒出来。以从大到小排序为例,第一轮比较后,所有数中最小的那个数就会浮到最右边;第二轮比较后,所有数中第二小的那个数就会浮到倒数第二个位置……就这样一轮一轮地比较,最后实现从大到小排序。 参考程序:
#include<iostream>
using namespace std;
int main() {
int n,exchange;
cout<<"要排几个数:";cin>>n;
int a[100];
for (int i=0; i<n; i++) {
cin>>a[i]; }
for(int i=1; i<=n-1; i++)
{
for(int j=1;j<=n-i;j++)
{
if(a[j-1]>a[j])
{exchange=a[j-1];
a[j-1]=a[j];
a[j]=exchange;
}
}
}
for(int i=0;i<n;i++)
{
cout<<a[i]<<" ";
}
}
3、选择排序法 1.选择排序法是将序列分为两段,有序前列和无序后列,每次查找无序后列中最大元素,将其插入到有序前列的最末尾处,直至无序后列最后一个元素,最终排序后的序列为降序序列
2.适用于包括数组和向量在内的序列
3.选择排序与冒泡排序的区别是选择排序每次遍历时会记住最大元素的位置,只进行一次交换,而冒泡排序每次遍历时会交换两个顺序不合法的元素 参考程序:
#include<iostream>
using namespace std;
int main() {
int n,exchange;
cout<<"要排几个数:";
cin>>n;
int a[100];
for (int i=0; i<n; i++) {
cin>>a[i];
}
for(int i=0;i<=n;i++)
{
for(int j=i+1;j<=n-1;j++)
{
if(a[i]>a[j])
{exchange=a[i];
a[i]=a[j];
a[j]=exchange;
}
}
}
for(int i=0; i<n; i++) {
cout<<a[i]<<" ";
}
}
其他排序方法还有快速排序法,挖坑填数+分治法 等方法。 本次上机实验使用的是冒泡排序法。 五、问题解决 1.在编写程序时,因为不熟练忽略了if…else的用法,当使用if…else if…之后使用了else,else后面不需要加括号并且在括号里面写入内容,否则会导致程序运行出错,下面提示的语句也不明显,系统认为是没加";"的原因,所以这个失误之处很容易被忽略,如果不注意到,很难改正它。以后编程更要留意一些简单语句的使用。 2.程序中使用了setw()函数,本意是使该函数置空格,使姓名和成绩之间有间隙,但当函数内部设置的数小时,该函数“似乎”不起作用,查阅资料后发现:当后面紧跟着的输出字段长度小于 n 的时候,在该字段前面用空格补齐,当输出字段长度大于 n 时,全部整体输出。
setw()的使用方法:
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
cout << setw(4) << "runoob" << endl;
cout << "runoob" << setw(4) << "runoob" << endl;
cout << setw(14) << "runoob" << endl;
cout << "runoob" << setw(14) << "runoob" << endl;
return 0;
}
上述代码输出结果
runoob
runoobrunoob
runoob
runoob runoob
扩充: setw() 默认填充的内容为空格,可以 setfill() 配合使用设置其他字符填充。
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
cout << setfill('*') << setw(14) << "runoob" << endl;
return 0;
}
以上代码输出结果为:
********runoob
六、实验总结 本次上机实验比以前的上机更为复杂,实验所需的程序功能较多,使用不同的函数来实现不同的功能,更加需要构造不同的逻辑功能,各自实现的程序也有与多种,可以进行深度探索。对于排序,有比较多的方法,可以分别进行尝试,选择出了最合适的一种。函数细节方面要更加在意,注意函数的正确用法,才能保证程序的正常运行。 参考链接:https://blog.csdn.net/yszdzjt/article/details/81563627 https://blog.csdn.net/shuwenting/article/details/81937423 https://www.runoob.com/w3cnote/cpp-func-setw.html
|