跟着NOAI考纲学Python,学完就能考,第13课

跟着NOAI考纲学Python,学完就能考,第13课

本文核心观点
NOAI 自学 Python 系列第 13 课:sorted() 与 list.sort()、key 参数、稳定排序、自定义排序规则。

跟着NOAI考纲学Python,学完就能考,第13课

每天一个知识点,带你自学NOAI,加入我们吧~

前面学了用模块调用现成的工具。但有些东西光会调用不够——NOAI考试会考你排序算法的原理。这节课先手写一个最基础的排序,再学Python自带的排序工具。

为什么要学排序

想想生活中哪些地方需要排序:考试成绩从高到低排名、找最大值最小值、数据去重……很多算法的第一步就是先排序。

NOAI考试不只考你会不会用Python排序,还会考排序算法的原理。所以我们先手写一个最经典的排序算法——冒泡排序。

冒泡排序

冒泡排序的思路很简单:从头到尾,两两比较相邻的元素,如果前面的比后面大,就交换。一轮下来,最大的数就"浮"到了最后面。再跑一轮,第二大的也归位了。重复几轮,整个列表就排好了。

冒泡排序就像排队——每一轮从头到尾两两比较,高的往后站。跑完一轮,最高的就到了最后面。再跑一轮,第二高的也归位了。

完整代码:

nums = [64342512221190]
n = len(nums)
for i in range(n - 1):
    for j in range(n - 1 - i):
        if nums[j] > nums[j + 1]:
            nums[j], nums[j + 1] = nums[j + 1], nums[j]
print(nums)

[11, 12, 22, 25, 34, 64, 90]

拆开看:

外层循环 for i in range(n - 1) — 总共跑 n-1 轮。7个数只需要6轮就能排好

内层循环 for j in range(n - 1 - i) — 每一轮两两比较相邻的数。因为每跑一轮,最后面就多一个已经排好的数,所以内层循环每轮可以少比一次

nums[j], nums[j+1] = nums[j+1], nums[j] — 交换两个元素。这是第10课学过的元组解包,一行搞定交换

if nums[j] > nums[j + 1] — 前面比后面大才交换,这样每轮最大的就"冒泡"到最后

用 sorted() 排序

手写冒泡排序是为了理解原理。实际写代码时,Python有现成的排序工具,一行搞定。

sorted() 接收一个列表,返回一个新的排好序的列表,原列表不变:

nums = [314159]
result = sorted(nums)
print(result)  # 新列表,排好了
print(nums)    # 原列表,没变

[1, 1, 3, 4, 5, 9]
[3, 1, 4, 1, 5, 9]

从大到小排?加一个参数 reverse=True

nums = [314159]
print(sorted(numsreverse=True))

[9, 5, 4, 3, 1, 1]

用 .sort() 排序

列表还有一个方法 .sort(),它直接修改原列表,不会创建新列表,返回值是 None

nums = [314159]
nums.sort()
print(nums)

[1, 1, 3, 4, 5, 9]

对比一下:

sorted(nums) — 返回新列表,原列表不动

nums.sort() — 改原列表,返回 None

这两个的区别是NOAI常考的知识点,必须记牢。

自定义排序

有时候不是简单地比大小。比如有一组学生成绩,想按分数排序:

students = [("小明"88), ("小红"95), ("小刚"72)]
result = sorted(studentskey=lambda xx[1])
print(result)

[('小刚', 72), ('小明', 88), ('小红', 95)]

key=lambda x: x[1] 的意思是:排序时按每个元素的第1个位置(也就是分数)来比大小。lambda 是一种写简单函数的快捷方式,现在知道怎么用就行,后面会详细讲。

易错点

错误1搞混 sort() 和 sorted()

sort() 改原列表,返回 Nonesorted() 不改原列表,返回新列表。最容易踩的坑:

nums = [312]
result = nums.sort()  # sort()返回None!
print(result)

None

列表确实排好了,但 result 拿到的是 None。想拿排好的结果,要么直接用 nums,要么用 sorted()

错误2冒泡排序的范围搞错

内层循环是 range(n - 1 - i),不是 range(n - 1)。写成 range(n - 1) 也能排对,但每一轮都会去比较已经排好的元素,浪费时间。考试时写 range(n - 1 - i) 更规范。

动手试试

自己先想,想完了香农平台上写代码跑一遍验证。

练习1:预测输出

下面这段代码运行后,屏幕上会输出什么?

a = [5281]
b = sorted(a)
a.sort(reverse=True)
print(b)
print(a)

提示:sorted() 返回新列表,sort() 改原列表。两个互不影响。

练习2:找bug

小明想把列表排好序后打印,但结果还是乱的。哪里出了问题?

nums = [312]
sorted(nums)
print(nums)

提示:sorted() 不改原列表,返回的新列表去哪了?

练习3:写代码

有一组学生成绩:

students = [("小明"88), ("小红"95), ("小刚"72), ("小华"90)]

把他们按分数从高到低排序,然后逐行打印每个人的名字和分数。

提示:用 sorted() + key= + reverse=True,然后用 for 循环打印。

去平台上手写代码

排序是算法的基础,也是考试的重点。回顾一下:

冒泡排序 — 两两比较、交换,手动实现排序

sorted(列表) — 返回新的排好序的列表,原列表不变

列表.sort() — 原地排序,直接改原列表

reverse=True — 降序排列

key= — 自定义排序规则

这篇文章讲的是香农NOAI学习平台"Python基础"模块的第十三课。平台上有更多的练习题,写完代码点运行,对不对立刻就知道。

香农NOAI学习平台
地址:shannon.arpa.school
微信扫码登录就能用,免费。
找到「Python基础」→「排序」,从第一道题开始写。

下一篇讲查找——在一堆数据里快速找到你要的东西。学完线性查找和二分查找,Python基础就全部过完了。

微信二维码

扫码备注【NOAI】加交流群