【问题描述】
参加计算机设计大赛的n个学校编号为1~ n,赛事分成m个项目,项目的编号为1~m.比赛获奖按照得分降序,取前三名,写一个统计程序产生各种成绩单和得分报表。
【基本要求】
1)每个比赛项目至少有10支参赛队;每个学校最多有6支队伍参赛;
2)能统计各学校的总分;
3)可以按照学校编号或名称,学校的总分、各项目的总分排序输出;
4)可以按学校编号查询学校某个项目的获奖情况;可以按项目编号查询取得前三名的学校;
5)数据存入文件并能随时查询
题目初步的思考
本题显然是排序题目,根据输入的学校,队伍,和队伍的得分进行排序,从而得出队伍和学校的排名。完成查询和统计的工作。但考虑到本题是完成排序任务,并记录排名,不需要写排序的完整过程,我想利用C++的STL中sort()函数完成排序任务。
补充sor()函数的用法
-
sort函数的使用必须加上头文件“#include< algorithm>”和“using namespace std;”,其使 用的方式如下:
sort(首元素地址(必填),尾元素地址的下一个地址(必填),比较函数(非必填));
可以看到,sot的参数有三个,其中前两个是必填的,而比较函数则可以根据需要填写,如果不写比较函数,则默认对前面给出的区间进行递增排序。
(1)基本数据类型数组的排序
若比较函数不填,则默认按照从小到大的顺序排序。如果想要从大到小来排序,则要使用比较函数cmp来告诉sort何时要交换元素。
#include <stdio.h> #include <algorithm> using namespace std; bool cmp(int a,int b){ return a > b; //可以理解为当a>b时把a放在b前面 } int main(){ int a[]={3,1,4,2}: sort (a,a 4,cmp); for(int i = 0;i < 4;i++){ printf("%d",a[i]); //输出4321 } return 0; }
记忆方法:如果要把数据从小到大排列,那么就用“<”,因为“a<b”就是左小右大;如果要把数据从大到小排列,那么就用“>”,因为“a>b”就是左大右小。而当不确定或者忘记时,不妨两种都试下,就会知道该用哪种了。
(2)结构体数组的排序
#include <stdio.h> #include <algorithm> using namespace std; struct node{ int x,y; }ssd[10]; bool cmp1(node a,node b){ return a.x>b.x;//按x值从大到小对结构体数组排序 } bool cmp2(node a,node b){//在x值相等的情况下,按照y的大小从小到大来排序(即二级排序) if(a.x != b.x) return a.x > b.x; else return a.y < b.y; } int main(){ ssd[0].x=2;//{2,2} ssd[0].y=2; ssd[1].x=1;//{1,3} ssd[1].y=3; ssd[2].×=3;//{3,1} ssd[2].y=1; sort(ssd,ssd+3,cmp);//排序 for(int i=0;i<3;i++){ printf("%d %d\n",ssd[i].x,ssd[i].y); } return 0; }
(3)容器的排序
在STL标准容器中,只有vector、.string、deque是可以使用sort的。这是因为像set、map这种容器是用红黑树实现的(了解即可),元素本身有序,故不允许使用sort排序。
#include <stdio.h> #include <algorithm> using namespace std; struct node{ int x,y; }ssd[10]; bool cmp1(node a,node b){ return a.x>b.x;//按x值从大到小对结构体数组排序 } bool cmp2(node a,node b){//在x值相等的情况下,按照y的大小从小到大来排序(即二级排序) if(a.x != b.x) return a.x > b.x; else return a.y < b.y; } int main(){ ssd[0].x=2;//{2,2} ssd[0].y=2; ssd[1].x=1;//{1,3} ssd[1].y=3; ssd[2].×=3;//{3,1} ssd[2].y=1; sort(ssd,ssd+3,cmp);//排序 for(int i=0;i<3;i++){ printf("%d %d\n",ssd[i].x,ssd[i].y); } return 0; }
排序题型的常见解法
-
相关结构体的定义 对排序题,一定会在题目中给出个体的许多信息,例如本题中有:学校ID、队伍ID、分数、排名等信息。这些信息在排序过程中一般都会用到,因此为了方便编写代码,常常将它们存至一个结构体当中,然后用结构体数组来表示多个个体。例如本题中子来说,就可以定义结构体类型Student,用以存放给定的信息。
struct School{ char id[20]; //学校ID int score; //分数 int rank; //排名 }stu[100010]; struct Team { char SchoolID[21];//学校ID char TeamID[10];//队伍ID int selection;//选择的参赛项目 int score;//该项目的得分 int rank;//该队伍在该项目上的排名 }team[100000];//参赛队伍
-
cmp函数的编写 众所周知,使用sot进行排序时,需要提供cmp函数实现的排序规则。
bool cmp(Team a, Team b) { if (a.score == b.score) return strcmp(a.TeamID, b.TeamID) < 0; else return a.score > b.score; }
-
很多排序题都会要求在排序之后计算出每个个体的排名,并且规则一般是:分数不同的排名不同,分数相同的排名相同但占用一个排位。对这种要求,一般都需要在结构体类型定义时就把排名这一项加到结构体中。于是在数组排序完成后就有下面两种方法来实现排名的计算:
①先将数组第一个队伍(假设数组下标从0开始)的排名记为1,然后遍历剩余队伍:如果当前队伍的分数等于上一个队伍的分数,那么当前队伍的排名等于上一个队伍的排名;否则,当前队伍的排名等于数组下标加1。对应的代码如下:
team[0].rank=1; for(int i = 1;i<n;i++){ if(team[i].score == team[i-1].score){ team[i].rank = team[i -1].rank; }else{ team[i].rank=i+1; } }
②而有时题目中不一定需要真的把排名记录下来,而是直接输出即可,那么也可以用这样的办法:令int型变量rank初值为1,然后遍历所有个体:如果当前队伍不是第一个队伍且当前队伍的分数不等于上一个队伍的分数,那么令rank等于数组下标加1,这时rank就是当前队伍的排名,直接输出即可。这样的做法适用于需要输出的信息过多,导致第一种方法代码冗长的情况。
int rank = 1; for(int i =0;i < n; i++){ if(i > 0 && team[i].score != team[i-1].score){ rank=i+1; } //输出当前个体信息,或者令team[1].rank=x也行 }