混乱的成绩表

题目描述

Zero 是一名学习委员,他负责很多有关学习上的任务,今天辅导员给了他一张成绩单,这个成绩单是按学号排序的,但是它是成绩单,应该按成绩排序。Zero 作为一个 acmer,对排序还算了解,但他想考考你,你能完成这个任务吗?

 输入

一个正整数 n,代表成绩单上学生的人数(n <= 2000)
接下来 n 行,每行两个整数 ID 和 x,ID是学生的编号(递增给出),x 是学生成绩 (0 <= x <= 100)

对于输入的数据,第一个整数n代表成绩单上学生的人数(即告诉我们需要存储的数据的量有:n个学号和n个成绩) 

接下来的n行,每行会输入两个整数分别代表学生的学号和成绩,有n行,自然要有n次读入,所以我们用循环读入,将读入的学号与成绩分别存入两个数组中(id与score)。每次循环读入两个数,分别存入id与score数组下标相同的位置,表示它们是同一个学生的信息。

全部读入完成后,就要对它们进行排序了(有一说一但凡能用Excel,这破代码是一行都不想多敲的)。

排序(重点) 

对于数组的排序,最基础的当属冒泡排序(或许一点也不基础,但确实是最早接触到的

冒泡排序(Bubble Sort)也是一种简单直观的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢"浮"到数列的顶端。

看不懂对不对?看不懂就对了,如果能看懂那我也不用大费周章地写这篇题解给你看了。

 再来看这个动图演示

 依旧看不懂对吧?那就不搞这些虚头八脑的东西了,好好看我写的题解。

排序不会,但比较大小和交换位置这两个操作,总该是会的吧

当给出一个数列:2 6 3 4 1,让你通过比较大小和交换位置,将这个数列变成递增序列,你会怎么做?

对喽,拿两个数比较它们的大小,如果前面的数大,就把后面的数放前面,前面的数放后面嘛

可是计算机不知道该拿哪两个数去比较怎么办?这还不好说,让它把所有数都比一遍就好啦

就以刚刚的2 6 3 4 1为例,我们先让2和6比大小,发现前面的2比后面的6要小,不用交换位置,然后再让6和3去比较,很明显,前面的6要比后面的3大,我们交换它们俩的位置,数列变成了2 3 6 4 1,下一步比较6和4的大小,交换6和4,数列变成了2 3 4 6 1,再比较6和1,交换6和1,数列变成了2 3 4 1 6

经过这轮操作,可以发现最大的6被换到了数列的最后面,如果我们再从头去进行比较、交换的操作,第二轮操作结束后,数列会变成2 3 1 4 6,第二大的4被放到了它该在的位置,那再来一轮呢?数列会变成2 1 3 4 6,第三大的3也被放到了它应该在的位置,这时我们不妨大胆猜测,每一轮操作,都会有一个数字被放到它应该在的位置。而第 i 轮被确定位置的数,就是这个数列中第 i 大的数。

这个猜测很大胆,但听起来也很合理,我们任意举的例子也都会符合这个猜测。那么,新的问题来了,我们最多需要进行多少轮操作,才能使这个数列变得有序呢?

如果每轮操作会将一个数字放到它该在的位置的话,要使有n个数字的数列变得有序,看起来似乎需要n轮操作,但是对于有n个数字的数列来说,它一共只有n个用于放数字的位置,如果有n - 1个数字都被放到了自己该在的位置,那剩下的一个数字既然还在这个数列里,那就一定在它应该在的位置上对叭。

所以,我们最多只需要进行n - 1轮操作,就可以将有n个数字的数列变得有序咯。

理论成立,让我们用代码来实现一下。

#include <stdio.h>

int a[110]; //定义一个数组用来存储数列中的元素,数组稍微开大一些

int main()
{
    int n, i, j; // i,j均为循环变量
    scanf("%d",&n); //变量n用于记录数列中一共有多少个元素

    for(i = 1; i <= n; i ++) //数组从下标为1的地方开始存储,a[1]即为数组的第一个元素
    {
        scanf("%d",&a[i]);
    }
    
    //此处的i用于记录当前进行到了第几轮循环,共需进行n - 1次循环
    for(i = 1; i <= n - 1; i ++)
    {
        //j作为数组下标,每轮循环的每次操作,比较数组中第j个元素和第j + 1个元素的大小
        /*注意此处j的范围,每轮操作结束会确定一个数的位置,位置已经确定的数不需要参与后续的操作
        另外我们每次比较的是第j个元素和第j个元素后面的元素(j + 1),所以j只需要枚举从1到未确 
        定位置的数的个数减一即可,比如刚开始有五个数,我们第一轮只需要比较四次,第二轮需要比较 
        三次(5 - 2次)。*/
        for(j = 1; j <= n - i; j ++)
        {
            //若前面的数大于后面的数,则交换两个数的位置
            if(a[j] > a[j + 1])
            {
                int b = a[j];
                a[j] = a[j + 1];
                a[j + 1] = b;
            }
        }
    }
    //输出排好序的数列(数组)
    for(i = 1; i <= n; i ++)
    {
        printf("%d ", a[i]);
    }
    return 0;
}

当学会上述算法(冒泡排序)后,我们就可以继续看这道明明可以用Excel解决却偏让我们去写代码的题了

还记得题目给了我们什么吗?对喽,一个整数n和n个学生的学号及成绩。

我们用变量n来存储学生的个数,用数组id来存储学生的学号,数组score来存储学生的成绩

然后根据题目要求进行排序操作

话说题目的要求是什么来着?噢对了,我还没放上来

输出

输出按成绩排名的成绩单,成绩越高,排名越靠前,相同成绩的人 ID 较小的排名在前

 既然要按成绩排名输出成绩单,我们自然要按成绩高低来排序

需要注意的是,在我们按照成绩排序的时候,交换成绩数组中元素位置的同时,学号也要跟着对应的成绩去交换,否则输出的时候会发现一个人的成绩和它的学号对不上号(这样搞的话就不是一个好班长咯)

另外,成绩排名,自然是成绩越高排名越靠前,所以我们要把分高的人放到最前面,注意不要搞反了哟

代码实现如下

#include<stdio.h>

int id[2010], score[2010];

int main()
{
    int n, i, j; //i,j为循环变量
    scanf("%d", &n);
    
    for(i = 1; i <= n; i ++)
    {
        scanf("%d%d", &id[i], &score[i]); //读入第i个学生的学号和成绩分别存入id和score数组中
    }
    
    //冒泡排序
    for(i = 1; i < n; i ++)
    {
        for(j = 1; j <= n - i; j ++)
        {
            //比较第j个学生和第j + 1个学生的分数,如果第j + 1个学生分数高则交换位置(排名)
            if(score[j] < score[j + 1])
            {
                //交换学号位置(排名)
                int x = id[j + 1];
                id[j + 1] = id[j];
                id[j] = x;
                
                //交换成绩位置(排名)
                x = score[j + 1];
                score[j + 1] = score[j];
                score[j] = x;
            }
        }
    }
    
    //按排名从高到低输出学生信息(注意换行)
    for(i = 1; i <= n; i ++)
    {
        printf("%d %d\n", id[i], score[i]);
    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值