实验一 绪论
一、实验目的与要求
1)熟悉C/C++语言(或其他编程语言)的集成开发环境;
2)通过本实验加深对算法时间复杂度的理解;
3)结合具体的问题分析算法时间复杂度。
二、实验内容
设计程序实现统计一个班的学生成绩(学生的人数可以设置3000、5000、8000、10000等测试数据),要求自行设计至少两种排序算法,实现如下四个功能;记录每种算法的耗时,结合数据结构的知识对两种算法的时间复杂度进行比较说明。
(1) 输入每个学生的学号,并随机生成2门课程的成绩;
(2) 计算每个学生的平均成绩和总成绩;
(3) 按总成绩从高到低排名,并按名次输出每个学生情况,包括:
学号,各科成绩,平均成绩,总成绩,排名
(4) 由键盘输入课程号,输出该课程成绩在90分(含90分)以上且总分在前3名的学生情况,要求能多次查询。
三、实验步骤
1)程序中可能遇到的头文件如下
#include<Windows.h> //windows头文件
#include<iostream> //引入一个流类库
#include<stdio.h> //标准输入输出头文件
#include<time.h> //导入时间库函数文件
2)提示代码
int array_Sort[ARRAY_MAXSIZE]; //声明待排序的数组
int array_Sort2[ARRAY_MAXSIZE];
for(int i=0;i<=ARRAY_MAXSIZE;i++){ //生成随机数组,大小为10000
......
}
for(int j=0;j<ARRAY_MAXSIZE;j++){ //生成递减数组,大小均为10000
......
}
clock_t start,end; //声明开始和结束的时间计数器
start=clock(); //排序开始时间计数器
end=clock(); //排序结束时间计数器
cout<<(double)(end-start)<<" ms"<<endl;//排序的时间
3)请将调试成功的源代码粘贴在下面
TEST:
#include<Windows.h> //windows头文件
#include<iostream> //引入一个流类库
#include<stdio.h> //标准输入输出头文件
#include<time.h> //导入时间库函数文件
#include<cstring>
#include<cstdlib>
using namespace std;class Student{int ** student;//二维数组:指针的指针 int x,y;//坐标
public://构造Student(int temp=0){x=temp;y=5;student=new int *[x];//坐标x int i=0;for(i=0;i<x;i++){student[i]=new int [y];//坐标y }}//输出void Show(){int i=0;for(i=0;i<x;i++){cout<<"学号:"<<student[i][0]<<"科目一成绩:"<<student[i][1]<<"科目二成绩:"<<student[i][2]<<"平均成绩:"<<student[i][3]<<"总成绩:"<<student[i][4]<<"排名:"<<student[i][5]+1<<endl; //student[i][5]初始化为i,输出时候+1}} //随机生成void Data(){int i=0;for(i=0;i<x;i++){student[i][0]=i;//学号 student[i][1]=rand()%100;//科目一成绩 student[i][2]=rand()%100;//科目二成绩 student[i][3]=(student[i][1]+student[i][2])/2;//平均分 student[i][4]=student[i][1]+student[i][2];//总分}} //总分排序:冒泡 void Rank(){int *temp,i=0,j=0;clock_t start,end;//声明开始和结束的时间计数器start=clock();//排序开始时间计数器for(i=0;i<x-1;i++){//外层,n个元素n-1次 for(j=0;j<x-i-1;j++){//内层,n个元素n-i次 if(student[j][4]<student[j+1][4]){temp=student[j];student[j]=student[j+1];student[j+1]=temp;}}}end=clock();//排序结束时间计数器cout<<"冒泡排序法所用时间:"<<(double)(end-start)<<" ms"<<endl;//排序的时间for(i=0;i<x;i++){student[i][5]=i;//初始化排名 }}//总分排序:选择void rank(){int *temp,maxno,i=0,j=0;clock_t start,end;//声明开始和结束的时间计数器start=clock();//排序开始时间计数器for(i=0;i<x-1;i++){//x个数,循环x-1次 maxno=i;//假设第i个最小 for(j=i+1;j<x;j++){if(student[j][4]>student[maxno][4]){maxno=j;}}temp=student[i];student[i]=student[maxno];student[maxno]=temp;}end=clock();//排序结束时间计数器cout<<"选择排序法所用时间:"<<(double)(end-start)<<" ms"<<endl;//排序的时间for(i=0;i<x;i++){student[i][5]=i;//初始化排名 }}//第四问1.0 /*void Problem(int subject=0){Student.rank();int num=0;//统计总分前三名 int flag=0;//标记符合条件存在情况 for(num=0;num<3;num++){if(student[num][subject]>=90){//第i个人这门课符合条件cout<<"学号:"<<student[num][0]<<"科目一成绩:"<<student[num][1]<<"科目二成绩:"<<student[num][2]<<"平均成绩:"<<student[num][3]<<"总成绩:"<<student[num][4]<<"排名:"<<student[num][5]<<endl;flag=1; }} if(flag==0){cout<<"该课程成绩在90分(含90分)以上且总分在前3名的学生不存在" <<endl;}}*//*//析构~Student(){int i=0;for(i=0;i<x;i++){delete [] student[i];student[i]=NULL;//删除指针的指针 }delete [] student;student=NULL;//删除指针 }*///第四问2.0 void Problem(int subject=0){int num=0;//统计总分前三名的counter int flag=0;//标记符合条件存在情况 for(num=0;num<3;num++){if(student[num][subject]>=90){//第i个人这门课符合条件cout<<"学号:"<<student[num][0]<<"科目一成绩:"<<student[num][1]<<"科目二成绩:"<<student[num][2]<<"平均成绩:"<<student[num][3]<<"总成绩:"<<student[num][4]<<"排名:"<<student[num][5]+1<<endl;flag=1; }} if(flag==0){cout<<"该课程成绩在90分(含90分)以上且总分在前3名的学生不存在" <<endl;}}
};int main(){cout<<"请输入学生人数:";int myx;cin>>myx;Student test(myx);//调用构造test.Data();//调用随机生成test.Rank();//调用冒泡test.Show();cout<<"请输入查询次数:";int checktime;cin>>checktime;int time; for(time=1;time<=checktime;time++){cout<<"请输入查询科目(科目一输入1,科目二输入2):";int sub;cin>>sub;test.rank();//调用选择 test.Problem(sub);//输出问题四的结果 }return 0;
}
4)运行结果分析
1.数组大小ARRAY_MAXSIZE为10000如下(截图运行结果):
2.数组大小ARRAY_MAXSIZE为8000如下(截图运行结果):
3.数组大小ARRAY_MAXSIZE为5000如下(截图运行结果):
4.数组大小ARRAY_MAXSIZE为3000如下(截图运行结果):
两种算法时间性能分析表:
方法 | 最好情况 | 最坏情况 | 平均情况 |
冒泡排序 | 10000人:277ms 8000人:165ms 5000人:53ms 3000人:17ms | 10000人:281ms 8000人:170ms 5000人:57ms 3000人:17ms | 10000人:279ms 8000人:167.5ms 5000人:55ms 3000人:17ms |
简单选择排序 | 10000人:150ms 8000人:87ms 5000人:26ms 3000人:9ms | 10000人:150ms 8000人:96ms 5000人:26ms 3000人:10ms | 10000人:150ms 8000人:91.5ms 5000人:26ms 3000人:9.5ms |
请针对上表进行分析与说明
分析:
在人为设置总人数为10000人、8000人、5000人、3000人的四个案例中,冒泡排序法的运算时间均大于简单选择排序法的运算时间,且总体来看冒泡排序法的运算时间是简单选择排序法的运算时间的1.5倍~2倍。
说明:
为了分析上述表格的结果,我们设元素个数为length,对上述表格的两种排序算法作如下的简要理解:
冒泡排序法运算法则为——从第一个值开始,依次轮询,相邻的两个数依次比较,如果大于(正序排序)或者小于(倒序排序)则交换位置,即每一次轮询都会把最大的一个数冒泡到最后,轮询次数为length-1,每次轮询的长度都会减1。
简单选择排序法运算法则为——从第一个值开始,依次轮询,每次轮询把当前值替换为最大值,轮询次数为length-1,每次轮询的长度都会减1。
通过对比我们容易发现,两种排序算法的时间复杂度都为O(n²),但二者的排序理念和结果大不相同,对此作以下两点分析与说明:
首先,从程序设计的思路来看,冒泡排序法通过相邻两个元素的逐一对比,从而进行大小排序,而简单选择排序法是以当前元素为基准,将其和后面的元素之一对比,在一定程度上会使得相同值的元素比较过程中两个元素的相对前后顺序位置受到影响。因而冒泡排序法相比于简单选择排序法而言在算法的思路理解和具体的编程过程上更为简单且容易理解,在实际运算的过程中更为稳定。
其次,从运算时间的长短来看,在内循环中,冒泡排序法每次都要交换元素的顺序,而简单选择排序法则只需要记录元素的下标,在一轮的比较只需要换一次位置。因而冒泡排序法的效率比简单选择排序法的效率低。上述表格的四种案例冒泡排序法的运算时间是简单选择排序法的运算时间的1.5倍~2倍的具体运算结果也证实了这条结论。
综上所述,在所需计算量较小或者是对运算时间无具体要求的情况下,我们可以优先选择冒泡排序法进行实践;在所需计算量较大或者是要求运算时间尽可能小的情况下,我们可以优先选择简单选择排序法进行实践。
其他参考代码:
#include<Windows.h> //windows头文件
#include<iostream> //引入一个流类库
#include<stdio.h> //标准输入输出头文件
#include<time.h> //导入时间库函数文件
#include<iomanip>
#include<cstdlib>#define ARRAY_MAXSIZE 5000 //定义学生的人数
#define STR_LENGTH 5
#define CLASS 2 //课程数量using namespace std;class Student{
private:string id;char classnum[CLASS];int scores[4];int rank;
public:Student();//学生信息的初始化void init1(int num);//产生随机数排序void init2(int num);//产生递减数列排序void setrank(int ran);int getrank();int getscore1();int getscore2();string getinfo();//显示学生的信息//运算符重载 friend bool operator<(const Student& s1,const Student& s2);//比较总成绩friend bool operator>(const Student& s1,const Student& s2);
};
Student::Student(){id="2021";classnum[0]='D';classnum[1]='S';for(int i=0;i<4;i++){scores[i]=0;}rank=0;
}
void Student::init1(int num){//随机//id初始化string temp=to_string(num);//id初始化id+=string(STR_LENGTH - temp.length(), '0');//前面补零id+=temp;//成绩初始化for(int i=0;i<CLASS;i++){scores[i]=rand()%101;}scores[2]=(scores[0]+scores[1])/2;scores[3]=scores[0]+scores[1];
}
void Student::init2(int num){//递减//id初始化string temp=to_string(num);//id初始化id+=string(STR_LENGTH - temp.length(), '0');//前面补零id+=temp;//成绩初始化scores[0]=100-0.01*num;scores[1]=100-0.01*num;scores[2]=(scores[0]+scores[1])/2;scores[3]=scores[0]+scores[1];
}void Student::setrank(int ran){rank=ran;
}int Student::getrank(){return rank;
}int Student::getscore1(){return scores[0];
}int Student::getscore2(){return scores[1];
}string Student::getinfo(){string info;string temp[4];for(int i=0;i<4;i++){temp[i]=to_string(scores[i]);}string str0=string(3 - temp[0].length(), ' ')+temp[0];string str1=string(3 - temp[1].length(), ' ')+temp[1];string str2=string(3 - temp[2].length(), ' ')+temp[2];string str3=string(3 - temp[3].length(), ' ')+temp[3];info="学号:"+id+"科目D成绩:"+str0+"科目S成绩:"+str1+"平均成绩:"+str2+"总成绩:"+str3+"排名"+to_string(rank);return info;
}bool operator<(const Student& s1,const Student& s2){return s1.scores[3]<s2.scores[3];
}
bool operator>(const Student& s1,const Student& s2){return s1.scores[3]>s2.scores[3];
} void bubble_sort(Student arr[]){ //冒泡排序//计算排序的时间clock_t start,end; //声明开始和结束的时间计数器start=clock(); //排序开始时间计数器 int i, j;for (i = 0; i < ARRAY_MAXSIZE - 1; i++){for (j = 0; j < ARRAY_MAXSIZE - 1 - i; j++){if (arr[j] < arr[j + 1]){Student temp;temp=arr[j];arr[j]=arr[j+1];arr[j+1]=temp;} }}end=clock(); //排序结束时间计数器cout<<"当前排序方法为冒泡排序"<<endl;cout<<"*************************"<<endl;cout<<"排序时间为:"<<setfill(' ')<<setw(10)<<(double)(end-start)<<" ms"<<endl;
}void insertion_sort(Student arr[]){ //插入排序//计算排序的时间clock_t start,end; //声明开始和结束的时间计数器start=clock(); //排序开始时间计数器 for(int i=1;i<ARRAY_MAXSIZE;i++){Student key=arr[i];int j=i-1;while((j>=0) && (key<arr[j])){arr[j+1]=arr[j];j--;}arr[j+1]=key;}end=clock(); //排序结束时间计数器cout<<"当前排序方法为插入排序"<<endl;cout<<"*************************"<<endl;cout<<"排序时间为:"<<setfill(' ')<<setw(10)<<(double)(end-start)<<" ms"<<endl;
}void selection_sort(Student arr[]){ //选择排序//计算排序的时间clock_t start,end; //声明开始和结束的时间计数器start=clock(); //排序开始时间计数器 for (int i = 0; i < ARRAY_MAXSIZE - 1; i++) {int min = i;for (int j = i + 1; j < ARRAY_MAXSIZE; j++)if (arr[j] > arr[min])min = j;Student temp;temp=arr[i];arr[i]=arr[min];arr[min]=temp;}end=clock(); //排序结束时间计数器cout<<"当前排序方法为插入排序"<<endl;cout<<"*************************"<<endl;cout<<"排序时间为:"<<setfill(' ')<<setw(10)<<(double)(end-start)<<" ms"<<endl;
}int main(){Student arrOfStu[ARRAY_MAXSIZE];while(1){//初始界面的展示cout<<"当前学生人数为:"<<setfill(' ')<<setw(15)<<ARRAY_MAXSIZE<<"人"<<endl;cout<<"********************************"<<endl;cout<<"1.进行学生学号成绩随机初始化****"<<endl<<endl;cout<<"2.进行学生学号成绩递减初始化****"<<endl<<endl;cout<<"3.进行学生成绩的排序 ****"<<endl<<endl;cout<<"4.按成绩从高到低输出学生情况****"<<endl<<endl;cout<<"5.输入课程号输出优秀学生 ****"<<endl<<endl;//输出该课程成绩在90分(含90分)以上且总分在前3名的学生情况,要求能多次查询cout<<"********************************"<<endl;int cho;cin>>cho;switch(cho){case 0:cout<<"欢迎下次使用"<<endl;//system("pause");return 0;break;case 1:srand((unsigned)time(NULL));for(int i=0;i<ARRAY_MAXSIZE;i++){arrOfStu[i].init1(i);}cout<<"随机初始化完成"<<endl;system("pause");system("cls");break;case 2:for(int i=0;i<ARRAY_MAXSIZE;i++){arrOfStu[i].init2(i);}cout<<"递减初始化完成"<<endl;system("pause");system("cls");break;case 3://排序的不同方法//bubble_sort(arrOfStu);//insertion_sort(arrOfStu);selection_sort(arrOfStu);for(int i=0;i<ARRAY_MAXSIZE;i++){arrOfStu[i].setrank(i+1);}system("pause");system("cls");break;case 4:if(arrOfStu[0].getrank()!=0){for(int i=0;i<ARRAY_MAXSIZE;i++){cout<<arrOfStu[i].getinfo()<<endl;}system("pause");system("cls");break;}else{cout<<"成绩未排名请排名后再操作"<<endl;system("pause");system("cls");break;}case 5:while(1){char c;cout<<"请输入课程号\n输入E结束"<<endl;cin>>c;if(c=='D'){if(arrOfStu[0].getrank()!=0){for(int i=0;i<3;i++){if(arrOfStu[i].getscore1()>=90){cout<<arrOfStu[i].getinfo()<<endl;}}}else{cout<<"成绩未排名请排名后再操作"<<endl;system("pause");system("cls");break;}}else{if(c=='S'){if(arrOfStu[0].getrank()!=0){for(int i=0;i<3;i++){if(arrOfStu[i].getscore2()>=90){cout<<arrOfStu[i].getinfo()<<endl;}}}else{cout<<"成绩未排名请排名后再操作"<<endl;system("pause");system("cls");break;}}else{if(c=='E'){break;}else{cout<<"输入错误请再次输入"<<endl<<endl;}}}}system("pause");system("cls");break;default:cout<<"输入错误,请再次输入"<<endl;system("pause");system("cls");break;}}return 0;
}