首先题目:
SDUT某实验室集训队的选拔又要开始了,集训队需要根据参加者的分数排名来决定谁能够进入集训队。 先要求你写一个自动排名的程序,根据每一个参与选拔的同学的分数进行排名,集训队需要根据大家的分数排名来决定谁能够进入集训队。
你能完成这个程序么?
输入格式:
输入的第一行为n ( 0<n<=50) ;
之后给出n 行,每行为一个人名和ta所得到的分数。保证没有相同的分数。
人名为英文单词,长度不超过10。
输出格式:
输出为n行,每行一个人名与他的得分。每一行最后没有多余的空格。
具体输出格式见样例。
输入样例:
3
Dan 10
John 50
Danny 30
输出样例:
John 50
Danny 30
而所写的代码:
#include <stdio.h>
#include <string.h>
int main() {
int n;
scanf("%d", &n);
if (0 < n && n <=50) {
char names[50][11];
int scores[50];
int i;
// 读取名字和分数
for (i = 0; i < n; i++) {
scanf("%s %d", names[i], &scores[i]);
}
// 根据分数对数组进行排序
for (i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (scores[j] < scores[j + 1]) { //冒泡排序对分数由高到低排序
// 交换名字和分数
//数组存储的是数组存储的,数组的下标是用来索引的
char tempName[11];
int tempScore;
strcpy(tempName, names[j]);
tempScore = scores[j];
strcpy(names[j], names[j + 1]);
scores[j] = scores[j + 1];
strcpy(names[j + 1], tempName);
scores[j + 1] = tempScore;
}
}
}
// 输出排名和分数
for (i = 0; i < n; i++) {
printf("%s %d", names[i], scores[i]);
if (i < n - 1) {
printf("\n");
}
}
}
return 0;
}
很多同学会不理解,在其中交换内容冒泡排序这一步的时候,为什么小于的话,要把这其中的名字和分数都要调换呢,而调换之后不是改变了顺序了吗。
其实此处,我们仔细来看的话,不变的是什么,变换的又是什么。
变化的是内容也就是 名字和分数
不变的scores数组的下标 和names字符串这里的下标
关注的也就是决定调换顺序的是分数,而数组的下标,作为索引,是始终保持着从小到大,也就是从第一名(或者说第0个)到最后一个的顺序,所以我们从大到小输出,借助的是数组下标的索引,由索引我们可以顺腾摸瓜,完成从大到小的输出,可是,不仅仅是借助这种索引完成从大到小的输出,我们数组中的内容也要完成从大到小的输出
简单来说,计算机这个东西从小到大输出,得借助这个索引
人看到的东西从小到大输出,得交换内容了就
所以,不变的是下下标,交换的是内容
至此,已成艺术
若再换一种风格 加入define 代码的可读性就更高了
#include <stdio.h>
#include <string.h>
#define MAX_NAME_LENGTH 10
#define MAX_PARTICIPANTS 50
int main() {
int n;
scanf("%d", &n);
if (0 < n && n <= MAX_PARTICIPANTS) {
char names[MAX_PARTICIPANTS][MAX_NAME_LENGTH + 1];
int scores[MAX_PARTICIPANTS];
int i;
// 读取名字和分数
for (i = 0; i < n; i++) {
scanf("%s %d", names[i], &scores[i]);
}
// 根据分数对数组进行排序
for (i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (scores[j] < scores[j + 1]) {
// 交换名字和分数
char tempName[MAX_NAME_LENGTH + 1];
int tempScore;
strcpy(tempName, names[j]);
tempScore = scores[j];
strcpy(names[j], names[j + 1]);
scores[j] = scores[j + 1];
strcpy(names[j + 1], tempName);
scores[j + 1] = tempScore;
}
}
}
// 输出排名和分数
for (i = 0; i < n; i++) {
printf("%s %d", names[i], scores[i]);
if (i < n - 1) {
printf("\n");
}
}
}
return 0;
}
最后我们看一个不规范的例子
#include<stdio.h>
struct mate{
int rank,score;
char name[10];
};
int main(){
int n;
scanf("%d",&n);
if(0<n&&n<=50){
int i,j;
struct mate per[n];
for(i=0;i<n;i++){
scanf("%s %d",per[i].name,&per[i].score);
per[i].rank=i+1;
}
int temp;
for(i=0;i<n;i++){
for(j=0;j<n-1;j++){
if(per[j].score>per[j+1].score){
temp=per[j].rank;
per[j].rank=per[j+1].rank;
per[j+1].rank=temp;
}
}
}
for(i=n;i>=0;i--){
for(j=0;j<n;j++){
if(i==per[j].rank&&per[j].rank!=1)
printf("%s %d\n",per[j].name,per[j].score);
else if(i==per[j].rank&&per[j].rank==1)
printf("%s %d",per[j].name,per[j].score);
}
}
}
return 0;
}
这里我们可见使用了结构体
这段代码哪里有不足呢
首先是结构体成员使用不当,这里结构体中定义了一个rank作为排名,这是排名,但是这段代码中当成了索引来使用,排名却不可以比较其中的内容,所以这就出现了弊端