一、概述
给出N个考生的考生号,德成绩和才成绩,根据规则排序输出。
排序题,但我一般用的只有冒泡排序。所以最开始就按最简单的模拟做法来做:开五个结构数组,输入然后判断,存入不同数组,存完之后对四个数组分别冒泡,再分别输出。先不考虑空间是否超了,只是时间复杂度就难以接受。对于最大值100000,冒泡需要的时间为一百亿的数量级,按一秒1Ghz,那么冒泡便需要一秒以上的时间,这样来说绝对会超时了,因此是不可取的。因此需要用到两个函数:cmp和sort。
二、分析
本题的考点在于,如何在规定时间内对大量数据进行排序,使用cmp和sort完成较好。
使用这两个函数,要添加头文件algorithm。
首先采用结构体保存每个学生的成绩,选择的变量类型有讲究。
struct TandV{
char ID_Number[10];
int Virtue_Grade;
int Talent_Grade;
int sum;
int flag;
}TV[100000];
首先是学生的考生号,注意到考生号是可能会比较大小的,同时它的位数固定,也较长,因此不推荐用long long int,使用string或者char较好,使用string时,比较大小函数用compare,使用char数组时,比较函数使用strcmp。我这里选择使用char,原因在于char数组可以使用scanf和%s输入,提高效率,string就只能用cin了,数量多时可能超时。
然后是成绩,简单使用int即可。
注意,为了便于分类,使用flag来区别不同的学生,同时有助于排序。这是极大提高效率和可读性的一步。
sort函数十分好用,它有三个变量,第一个是待排数组的首地址,第二个是末地址的下一个地址,第三个是cmp函数的返回值。
如果不填入cmp那个变量,sort默认是从小到大对数组元素进行排序。如果想按其他方式排序呢?这就是我们使用cmp函数的意义。
cmp函数,实际上就是一种规则,规定了如何排序,常见的cmp函数长这样
bool cmp(int a,int b)
{
return a<b;//按从小到大排列
}
复杂一点的cmp函数长这样
bool cmp(Stu a,Stu b)
{
if(a->math!=b->math)
return a->math<b->math;//按数学成绩从小到大排列
else
return a->chinese>b->chinese;//如果数学成绩相同,按语文成绩从小到大排列
}
注意到cmp的返回值是bool类型,这意味着它只返回对或者错,那么即使不了解sort的工作原理,我们也可以想象,cmp就是负责告诉sort是否要换两个元素位置,如果返回真,则交换,返回假,则不交换(当然也可能反过来),那么重点就在cmp上了,cmp负责看到底交换不交换两个元素,我们的逻辑主要也在这上面。代码如下:
bool cmp(TandV a,TandV b)
{
if(a.flag!=b.flag)//如果不是同一组
return a.flag<b.flag;//按圣人、君子、愚人、小人排序
else if(a.sum!=b.sum)
return a.sum>b.sum;//同一组,按总分排序
else if(a.Virtue_Grade!=b.Virtue_Grade)
return a.Virtue_Grade>b.Virtue_Grade;//同一组且总分相同,按德成绩排序
else
return strcmp(a.ID_Number,b.ID_Number)<0;//都相同,按学号排序
}
注意以下几点:
if的判断条件都是!=,不是大于或小于;
return后面不是int时,char比较不能只把strcmp放上,要加上<0,这说明是按考生号从小到大排列,>0就是从大到小排列了。
然后是分类,给flag赋值。代码如下:
if(TV[i].Virtue_Grade<L||TV[i].Talent_Grade<L)
TV[i].flag=5;
else if(TV[i].Virtue_Grade>=H&&TV[i].Talent_Grade>=H)
{
TV[i].flag=1;
_num++;
}
else if(TV[i].Virtue_Grade>=H&&TV[i].Talent_Grade<H)
{
TV[i].flag=2;
_num++;
}
else if(TV[i].Virtue_Grade<H&&TV[i].Talent_Grade<H&&TV[i].Virtue_Grade>=TV[i].Talent_Grade)
{
TV[i].flag=3;
_num++;
}
else
{
TV[i].flag=4;
_num++;
}
注意一点,判断条件的顺序不能出错,要首先判断是不是都大于等于L,这样下面的条件可以简单不少;
再之后就是输入数据,排序和输出了。
有了sort函数,排序变得简单了很多啊,也不需要自己去苦兮兮的去写垃圾的冒泡了。
三、总结
要重视cmp和sort的使用,排序题中很常用,很重要,同时注意char数组的比较。
PS:代码如下:
#include<stdio.h>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
struct TandV{
char ID_Number[10];
int Virtue_Grade;
int Talent_Grade;
int sum;
int flag;
}TV[100000];
bool cmp(TandV a,TandV b)
{
if(a.flag!=b.flag)//如果不是同一组
return a.flag<b.flag;//按圣人、君子、愚人、小人排序
else if(a.sum!=b.sum)
return a.sum>b.sum;//同一组,按总分排序
else if(a.Virtue_Grade!=b.Virtue_Grade)
return a.Virtue_Grade>b.Virtue_Grade;//同一组且总分相同,按德成绩排序
else
return strcmp(a.ID_Number,b.ID_Number)<0;//都相同,按学号排序
}
int main()
{
long int num;
scanf("%ld",&num);
int H,L;
scanf("%d %d",&L,&H);
int i;
long int _num=0;
for(i=0;i<num;i++)
{
scanf("%s %d %d",&TV[i].ID_Number,&TV[i].Virtue_Grade,&TV[i].Talent_Grade);
TV[i].sum=TV[i].Talent_Grade+TV[i].Virtue_Grade;
if(TV[i].Virtue_Grade<L||TV[i].Talent_Grade<L)
TV[i].flag=5;
else if(TV[i].Virtue_Grade>=H&&TV[i].Talent_Grade>=H)
{
TV[i].flag=1;
_num++;
}
else if(TV[i].Virtue_Grade>=H&&TV[i].Talent_Grade<H)
{
TV[i].flag=2;
_num++;
}
else if(TV[i].Virtue_Grade<H&&TV[i].Talent_Grade<H&&TV[i].Virtue_Grade>=TV[i].Talent_Grade)
{
TV[i].flag=3;
_num++;
}
else
{
TV[i].flag=4;
_num++;
}
}
sort(TV,TV+num,cmp);
printf("%ld\n",_num);
for(i=0;i<_num;i++)
{
printf("%s %d %d\n",TV[i].ID_Number,TV[i].Virtue_Grade,TV[i].Talent_Grade);
}
}