1.相关结构体的定义
对排序题,一定会在题目中给出个体的许多信息,例如学生有姓名、准考证号、分数、排名等信息。这些信息在排序过程中一般都会用到,因此为了方便编写代码,常常将它们存至一个结构体当中,然后用结构体数组来表示多个个体。例如对上面学生的例子来说,就可以定义结构体类型 Student,用以存放给定的信息:
struct Student {
char name[10];//姓名
char id[10];//准考证号
int score;//分数
int r;//排名
}stu[10000];
2.cmp函数的编写
众所周知,使用sort进行排序时,需要提供cmp函数实现的排序规则。在考试的排序题中,经常会出现类似这样的要求:对所有学生先按分数从高到低排序,分数相同的按姓名的字典序从小到大排序。
以上段提到的要求为例,实际上需要完成的排序规则可以等价表述如下:
①如果两个学生分数不相同,那么分数高的排在前面。
②否则,将姓名字典序小的排在前面。
由此可以很容易地写出对应的cmp函数:
bool cmp(Student a,Student b){
if(a.score != b.score)
return a.score>b.score;
else
return strcmp(a.name,b.name)<0;
}
关于 strcmp函数需要做出如下解释: strcmp函数是 string. h头文件下用来比较两个char型数组的字典序大小的,其中 strcmp(strl,st2)当strl的字典序小于st2时返回一个负数,当strl的字典序等于st2时返回0,当stl的字典序大于st2时返回一个正数。而有些读者可能对cmp函数中的 strcmp( a.name, b.name)0的部分不太理解,事实上这与普通变量的写法是一致的。试想,如果字符数组可以直接进行比较,那么当需要按字典序从小到大排序时,就会在cmp函数里写类似 return a.name<b.name的写法,表示a.name的字典序小于b.name的字典序。那么,当使用 strcmp进行比较时,实际上采用的也是同一个思路,即使用 strcmp( a nameb.name)<0表示a.name的字典序小于b.name的字典序。唯一需要注意的是, strcmp的返回值不一定是-1或是+1(这与编译器有关),因此 return strcmp(a.name,b.name)=-1的写法是错误的。
3.排名的实现
很多排序题都会要求在排序之后计算出每个个体的排名,并且规则一般是:分数不同的排名不同,分数相同的排名相同但占用一个排位。例如有五个学生的分数分别为90、88、88、88、86,那么这五个学生的排名分别为1、2、2、2、5。
对这种要求,一般都需要在结构体类型定义时就把排名这一项加到结构体中(正如上文中 Student类型的定义一样)。于是在数组排序完成后就有下面两种方法来实现排名的计算:
①先将数组第一个个体(假设数组下标从0开始)的排名记为1,然后遍历剩余个体:如果当前个体的排名等于上一个个体的排名,那么当前个体的排名等于上一个个体的排名;否则,当前个体的排名等于数组下标加1。对应的代码如下:
stu[0].r = 1;
for(int i=1;i<n;i++){
if(stu[i].score == stu[i-1].score){
stu[i].r = stu[i-1].r;
}else{
stu[i].r = i+1;
}
}
②而有时题目中不一定需要真的把排名记录下来,而是直接输出即可,那么也可以用这样的办法:令int型变量r初值为1,然后遍历所有个体:如果当前个体不是第一个个体且当前个体的分数不等于上一个个体的分数,那么令等于数组下标加1,这时r就是当前个体的排名,直接输出即可。这样的做法适用于需要输出的信息过多,导致第一种方法代码冗长的情况。
int r = 1;
for(int i = 0;i<n;i++){
if(i>0&&stu[i].score!=stu[i-1].score){
r = i+1;
}
//输出当前个体信息,或者零stu[i].r=r也行
}