raptor输入n个数据排序_C++:数据排序基础

日常生活中,我们经常需要给数据排序 (sorting)。举一个简单的例子:

在某世界一流大学,教务部想要了解学生的内卷情况,因此抽取了 6 名学生,通过他们平时卷出的学习成绩计算出他们的平均内卷点数 (Involutionary Point Average, IPA),在 Excel 上制成了如下所示的表格:

6c7b27e512b2e29ae8878061fdad7186.png

现在要给这 6 名学生的 IPA 排个序,这在 Excel 上是很好操作的,只需要:(演示的软件为 Microsoft Office 2019 for Mac,可能与 Windows 上的有区别)

知乎视频​www.zhihu.com

这样排序以后,不仅 IPA 的数值降序排列了,而且 IPA 和 Name 的对应关系没有搞乱。

当然,我接下来要讲的肯定不是 Excel,而是用 C++ 实现数据的排序。


案例分析 1(冒泡排序)

我们先看一个简单一点的例子:只将数据排序,而不涉及数据与「名称」之间的对应。


问题描述:

输入一组整数(共 n 个),写程序将这组数降序输出。

关于输入:

输入分为两行:第一行是待排序的整数的总个数 n,第二行是这 n 个数,以空格分隔。

关于输出:

输出共一行,即将这 n 个数由大到小排列。数与数之间以空格分隔。

输入示例:

5
3 4 2 5 1

输出示例:

5 4 3 2 1 

要解决这个问题,我们很自然地想到运用循环结构。因为使数据降序输出的实质就是依次从这组数中找到最大者、次大者、第三大者……,然后按照它们的排位依次输出。显然这是一个重复寻找的过程,需要循环结构来实现。

很明显题中所给的 n 就是循环的次数,那么程序中肯定包括一句:

for 

此外,为了便于输入后存储下来,构建一个数组也是有必要的。

int 

然后接一个 for 循环把这组数输入数组。

这部分都容易想到,关键是排序部分的 for 循环要怎么写。也就是,在每一轮循环中,要怎么找出那个尚未输出的最大数。

显然,如果拿最大数和数组中的任何一个数去比较,最大数都将大于等于那个数。

因此,将数组中的每个数单独拿出来与数组中的所有数逐一比较,最大数「击败」(指大于等于)所比较的数的次数为 n,次大数为 n - 1,第三大数为 n - 2,……,最小的数为 1,它只能大于等于自己。(如果数据各不相同的话)

按照这个思路,我们只需要依次输出「击败」次数为 n, n - 1, n - 2, ... ,1 的数就可以了。而这需要「将数组中的每个数单独拿出来与数组中的所有数逐一比较」——也就意味着,我们需要两层循环。(第一层是「每个数都单独拿出来」,第二层是「单独拿出来的数和每个数逐一比较」)然后我们还需要一个数组 beat[n],来记每个数「击败」的次数。

那么我们可以写出这个逐一比较的双重循环:

for 

然后我们还需要一个输出的循环。我们已经有了「击败」数 beat[i] 作为每个数的「排位」,那么我们每次使排位 - 1 就可以依次输出了。排位 - 1 需要一个 for 循环,找到对应的 i 又需要一个循环,因此这也是一个双重循环:

for 

可能有重复数据导致排位相等的情况,但是相等者会一并输出,所以没有问题。

完整的参考代码如下:

左右滑动代码块以阅读完整内容。
#include 

sort 函数

当然,我们上面的做法是比较复杂的(还不如 Excel)。实际上有一个函数可以给数组进行排序,它就是 sort 函数。

sort 函数包含在头文件

#include 

中,它的使用方法如下:

sort 

用这个函数做上面的案例分析 1 是很简单的,只需要十几行就可以写出来,这里不再赘述。


案例分析 2

现在我们来解决之前提到的 IPA 排序的问题:

6c7b27e512b2e29ae8878061fdad7186.png

问题描述:

输入一组学生的 IPA 值,要求将它们的 IPA 值(对应到学生的名字)降序输出。

关于输入:

输入分为两行:第一行是待排序的学生的总个数 n,之后的 n 行中,每一行依次为学生 A, B, C, ... 的 IPA 值,为两位小数。输入保证 n <= 26。

关于输出:

输出共 n 行,每一行都包括一个学生的名字(A, B, C, ... )以及他/她的 IPA 值(两位小数),两者以空格分隔;所有行按照 IPA 值降序排列。

输入示例:

6
3.99
4.00
3.95
3.92
3.98
3.90

输出示例:

B 4.00
A 3.99
E 3.98
C 3.95
D 3.92
F 3.90

这里因为要对应到「名字」输出(相当于 i 和 a[i] 的对应不能弄乱),所以只用 sort 是不行的。而我们在案例分析 1 中,没有改变 i 和 a[i] 的对应,因此可以借鉴之前的思路来解决这个问题。

我们注意到输入是按 A, B, C, D, ... 的顺序进行的,它们可以被一个 for 循环分别读入到一个数组 a[i] 的第 0, 1, 2, 3, ... 位中去,而这些字母的 ASCII 码也是递增的关系,所以 i 值和名字是可以对应的。具体来说就是:定义一个 char m = 'A',输出 a[i] 的同时输出 (char) (m + i) 就行了。

那么对上面的程序稍作修改,把 int 变成 float 或 double,再控制两位小数就可以了。参考代码如下:(没写注释了)

左右滑动代码块以阅读完整内容。
#include 

在这种情况下,sort 函数反而会使程序更复杂了。(我们在讨论类似的问题的时候,已经有同学试过了)


练习:称体重

如果你有北大编程网格的账号,可以直接到下面的网站里做题:

http://www.pkupc.cn/programming/problem/95ea5733b34344e0a3cc68f0f19d7256/show.do​www.pkupc.cn

描述:

赵、钱、孙、李四个人中既有大人也有小孩,给他们称体重时发现,他们每个人的体重都不一样,且体重(单位:公斤)恰好是 10 的整数倍,且他们的体重都不高于 50 公斤,已知赵、钱两人的体重之和恰好等于孙、李两人的体重之和;赵、李两人的体重之和大于孙、钱两人的体重之和,并且赵、孙俩人的体重之和还小于钱的体重。
请编写一个程序,按照由大到小的顺序,打印出四人的姓氏的首字母和体重数(中间用空格隔开,每人一行)。

关于输出:

打印出四人的姓氏的首字母和体重数(中间用空格隔开,每人一行)。

输出示例:(不一定是正确答案)

z 10
q 20
s 30
l 40

解析:

本题综合了计算机的解题逻辑和数据的排序。

参考代码如下:

左右滑动代码块以阅读完整内容。
#include 

输出结果应该是

l 50
q 40
z 20
s 10
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值