目录
题目(有点长,可以跳过看下面的思路)
问题描述
给定多个比赛项目的不同国家和地区代表队运动员成绩,总结奥运奖牌榜。请编写一个函数AdjustSortTable,将奖牌榜按照规定的规则进行重新排序。函数声明如下:
void AdjustSortTable(int aSortTable[],struct medalCountry aMedalCountry[], int iCounter, int iNo, int iMedalType);
返回值:
无
参数:
AdjustSortTable:输入/输出参数,输入表示待重排数组,输出表示重排序后的数组
aMedalCountry:表示当前奖牌数目刚刚发生变化的代表队
iCounter:表示当前奖牌榜上总共有的代表队数目
iNo:表示当前奖牌数目刚刚发生变化的代表队目前在奖牌榜中的位置序号
iMedalType:表示当前奖牌数目刚刚发生变化的代表队刚刚获得的奖牌类型,其值为GOLDMEDAL(值0)代表金牌,SILVERMEDAL(值1)代表银牌,BRONZEMEDAL(值2)代表铜牌。
注意:函数声明已包含在主程序中,不需要自己定义。只需要提交自定义的函数代码。
主程序如下:
主函数输入格式
输入的第一行包含一个整数n,表示给出了n个比赛项目的前三名所属代表队信息。
第二行起的n行给出了n个比赛项目的金银铜牌运动员所属代表队信息,每行包含3个字符a1, a2, a3,表示金银铜牌运动员所属代表队代号,相邻的代号之间用一个空格分隔。
主函数输出格式
输出优先按照金牌数,金牌数相同的按照银牌数,金银牌数目都相同的按照铜牌数从多到少,金银铜牌都相同的按照代号字母顺序排出的奥运奖牌棒。每个国家输出一行,每行包括名次、代表队代号、金牌数、银牌数、铜牌数信息,每项信息占用3个字符长度。
样例输入
8
A B C
C C A
D B C
A D E
A C F
I G H
A D C
C B F
样例输出
1 A 4 0 1
2 C 2 2 3
3 D 1 2 0
4 I 1 0 0
5 B 0 3 0
6 G 0 1 0
7 F 0 0 2
8 E 0 0 1
9 H 0 0 1
样例说明
在给出的8个项目中,A有4项拿到了金牌,所以排位第1位;D、I的金牌数相同,按银牌数排序,D在I前;E、H的金银铜牌个数均相同,E的字母顺序在H前,因此E排在前。
评测用例规模与约定
1 ≤ n ≤ 303,每个代表队用一个或两个字母代替,总代表队数小于等于206个。
主函数
#include <stdio.h> #include <string.h> struct medalCountry{ int iPlace; char sName[3]; int iMedalNum[3]; }; enum medalType{ GOLDMEDAL , SILVERMEDAL, BRONZEMEDAL}; void AdjustSortTable(int aSortTable[],struct medalCountry aMedalCountry[], int iCounter, int iNo, int iMedalType); int main(void) { int n,i,j,counter=0; struct medalCountry aMedalCountry[206]={0}; struct medalCountry *pSMC; int aSortTable[206]; char sNameTmp[3]; scanf("%d",&n); for(i=0; i<n; i++) { //Gold Medal scanf("%s",sNameTmp); for(j=0; j<counter;j++) { if(!strcmp(aMedalCountry[j].sName, sNameTmp)) { aMedalCountry[j].iMedalNum[GOLDMEDAL]++; AdjustSortTable(aSortTable, aMedalCountry, counter, j, GOLDMEDAL); break; } } if(j==counter) { strcpy(aMedalCountry[j].sName, sNameTmp); aMedalCountry[j].iMedalNum[GOLDMEDAL]++; aSortTable[j]=j; counter++; AdjustSortTable(aSortTable, aMedalCountry, counter, j, GOLDMEDAL); } //Silver Medal scanf("%s",sNameTmp); for(j=0; j<counter;j++) { if(!strcmp(aMedalCountry[j].sName, sNameTmp)) { aMedalCountry[j].iMedalNum[SILVERMEDAL]++; AdjustSortTable(aSortTable, aMedalCountry, counter, j, SILVERMEDAL); break; } } if(j==counter) { strcpy(aMedalCountry[j].sName, sNameTmp); aMedalCountry[j].iMedalNum[SILVERMEDAL]++; aSortTable[j]=j; counter++; AdjustSortTable(aSortTable, aMedalCountry, counter, j, SILVERMEDAL); } //Bronze Medal scanf("%s",sNameTmp); for(j=0; j<counter;j++) { if(!strcmp(aMedalCountry[j].sName, sNameTmp)) { aMedalCountry[j].iMedalNum[BRONZEMEDAL]++; AdjustSortTable(aSortTable, aMedalCountry, counter, j, BRONZEMEDAL); break; } } if(j==counter) { strcpy(aMedalCountry[j].sName, sNameTmp); aMedalCountry[j].iMedalNum[BRONZEMEDAL]++; aSortTable[j]=j; counter++; AdjustSortTable(aSortTable, aMedalCountry, counter, j, BRONZEMEDAL); } } for(i=0; i<counter; i++) { aMedalCountry[aSortTable[i]].iPlace = i; pSMC=aMedalCountry+aSortTable[i]; printf("%3d %3s %3d %3d %3d\n", pSMC->iPlace+1, pSMC->sName, pSMC->iMedalNum[GOLDMEDAL], pSMC->iMedalNum[SILVERMEDAL], pSMC->iMedalNum[BRONZEMEDAL]); } return 0; }
思路
题干分析
要写出这个题目,我们不妨先来看看主程序在说什么:
首先,题目要求我们输入n场比赛信息,接着为每位获奖队伍添加相应的奖牌
//Gold Medal
scanf("%s",sNameTmp);
for(j=0; j<counter;j++)
{
if(!strcmp(aMedalCountry[j].sName, sNameTmp))
{
aMedalCountry[j].iMedalNum[GOLDMEDAL]++;
AdjustSortTable(aSortTable, aMedalCountry, counter, j, GOLDMEDAL);
break;
}
}
if(j==counter)
{
strcpy(aMedalCountry[j].sName, sNameTmp);
aMedalCountry[j].iMedalNum[GOLDMEDAL]++;
aSortTable[j]=j;
counter++;
AdjustSortTable(aSortTable, aMedalCountry, counter, j, GOLDMEDAL);
}
由于金银铜的奖牌代码没有很大区别,我们这里仅仅拿金牌举例:
第一个循环里,我们在已知的队伍列表中检查有无该队伍
例如样例中的第一行
A B C
读入 A 后,我们在 iMedalCountry结构数组中找到相应的队伍,所以添加了 A,并且递增 counter,接着使用 AdjustSortTable() 函数进行排序。
函数主体
知识补充
这里我们要先知道一个新的排序 表排序 ,什么是表排序呢?这个排序实际上更多体现的是一种间接排序的概念。我们知道,如果排序一个整形数组,可能直接排序元素会很快,可是,如果我们现在排序的元素是一个很大的结构体呢?这时对其进行排序,我们就不能忽略元素复制移动的时间了,因此表排序应运而生。是不是很熟悉,现在知道函数参数里面的 aSortTable 数组是干什么的了吧?
在表排序里,我们排序的并非元素本身,而是排序他们对应的 “指针”,这个不是我们学的的地址指针,而是一个 数组的下标。具体的内容我这里不做过多结束,感兴趣的同学可以看看下面的博文
正式内容
说了这么多,其实函数本身排序并不难,我们可以使用插入排序
void AdjustSortTable(int aSortTable[], struct medalCountry aMedalCountry[], int iCounter, int iNo, int iMedalType) {
for (int i = 1; i < iCounter; i++) {
int j, tmp = aSortTable[i]; //store the element which is ready for insertion
for (j = i; j > 0; j--) {
if (aMedalCountry[tmp].iMedalNum[0] > aMedalCountry[aSortTable[j - 1]].iMedalNum[0]) { //compare gold medals
aSortTable[j] = aSortTable[j - 1];
}
else if (aMedalCountry[tmp].iMedalNum[0] == aMedalCountry[aSortTable[j - 1]].iMedalNum[0]) { //compare sliver medals
if (aMedalCountry[tmp].iMedalNum[1] > aMedalCountry[aSortTable[j - 1]].iMedalNum[1]) {
aSortTable[j] = aSortTable[j - 1];
}
else if (aMedalCountry[tmp].iMedalNum[1] == aMedalCountry[aSortTable[j - 1]].iMedalNum[1]) {
if (aMedalCountry[tmp].iMedalNum[2] > aMedalCountry[aSortTable[j - 1]].iMedalNum[2]) { // compare bronze medals
aSortTable[j] = aSortTable[j - 1];
}
else if (aMedalCountry[tmp].iMedalNum[2] == aMedalCountry[aSortTable[j - 1]].iMedalNum[2]) {
if (strcmp(aMedalCountry[tmp].sName, aMedalCountry[aSortTable[j - 1]].sName) < 0) {
aSortTable[j] = aSortTable[j - 1];
}
else break; //don't forget break
}
else break;
}
else break;
}
else break;
}
aSortTable[j] = tmp;
}
}
要注意里面的条件比较,和 break语句就好,我这里没有使用 iNo 和 iMedalType,直接全部重新排序,当然,我们也可以先判断 iMedalType来对排序进行修剪,可以一定程度上缩短运行时间。这里附上一位大佬的代码,大家可以看看,他事先进行了判断,不过他使用的排序是冒泡排序。
结语
期末考马上就要来了,大家都有做好准备吗,不过不管结果如何,尽力了就好,白云我呢 ,在这里预祝大家都能考到理想的成绩!