对python的再认识-基于数据结构进行-a003-列表-排序

Python 列表排序

本文聚焦 Python 列表的排序操作,包含 sort()sorted() 的对比、自定义排序、多级排序、排序稳定性及性能分析。

我也将给出个人思维导图

一、基础用法

1.1 sort() vs sorted()

方法 类型 返回值 是否修改原列表
list.sort() 方法 None 是(原地排序)
sorted(list) 内置函数 新列表
python 复制代码
nums = [3, 1, 4, 1, 5, 9]

# sort() - 原地排序
nums.sort()
print(nums)  # [1, 1, 3, 4, 5, 9]
# sort() 返回 None
result = nums.sort()
print(result)  # None

# sorted() - 返回新列表
nums = [3, 1, 4, 1, 5, 9]
sorted_nums = sorted(nums)
print(sorted_nums)  # [1, 1, 3, 4, 5, 9]
print(nums)         # [3, 1, 4, 1, 5, 9] - 原列表不变

注意sort() 返回 None 是有意设计,强制开发者区分原地操作和返回新值。

1.2 反向排序

python 复制代码
nums = [3, 1, 4, 1, 5, 9]

# 方法 1:reverse 参数
nums.sort(reverse=True)
# [9, 5, 4, 3, 1, 1]

# 方法 2:sorted + reverse
nums = [3, 1, 4, 1, 5, 9]
desc = sorted(nums, reverse=True)
# [9, 5, 4, 3, 1, 1]

# 方法 3:先排序再反转(不推荐,多一次操作)
nums = [3, 1, 4, 1, 5, 9]
nums.sort()
nums.reverse()
# [9, 5, 4, 3, 1, 1]

1.3 字符串列表排序与字典序

字典序(Lexicographic Order):从左到右逐字符比较,Unicode 码点小的排在前面。

python 复制代码
# 基础字典序排序
words = ['banana', 'apple', 'cherry']
words.sort()
# ['apple', 'banana', 'cherry']

# 大小写敏感(ASCII: 'A'=65, 'a'=97)
words = ['banana', 'Apple', 'cherry']
words.sort()
# ['Apple', 'banana', 'cherry'] - 大写字母排在前面

# 数字 < 大写 < 小写
chars = ['9', 'A', 'a', 'Z', 'z']
chars.sort()
# ['9', 'A', 'Z', 'a', 'z']
# ASCII: '9'=57, 'A'=65, 'Z'=90, 'a'=97, 'z'=122

# 前缀相同,短的排在前面
words = ['a', 'aa', 'aaa']
words.sort()
# ['a', 'aa', 'aaa']

# 不区分大小写
words = ['banana', 'Apple', 'cherry']
words.sort(key=str.lower)
# ['Apple', 'banana', 'cherry']

# 按最后一个字符排序
words = ['abc', 'def', 'xyz']
words.sort(key=lambda s: s[-1])
# ['abc', 'def', 'xyz']  # c < f < z

注意 :不同类型元素的列表无法排序,会抛出 TypeError


二、自定义排序

2.1 key 参数

key 指定一个函数,用于提取比较键:

python 复制代码
# 按字符串长度排序
words = ['python', 'java', 'c', 'javascript']
words.sort(key=len)
# ['c', 'java', 'python', 'javascript']

# 按绝对值排序
nums = [3, -5, 2, -1, 4]
nums.sort(key=abs)
# [-1, 2, 3, 4, -5]

# 按字符串中数字部分排序
items = ['item123', 'item45', 'item6']
items.sort(key=lambda s: int(s[4:]))
# ['item6', 'item45', 'item123']

# 按倒数第二字符排序
words = ['abc', 'xyz', 'def']
words.sort(key=lambda s: s[-2])
# ['abc', 'def', 'xyz']

2.2 使用 lambda 函数

python 复制代码
# 按嵌套列表的某个元素排序
students = [['Alice', 85], ['Bob', 92], ['Charlie', 78]]
students.sort(key=lambda s: s[1])  # 按成绩
# [['Charlie', 78], ['Alice', 85], ['Bob', 92]]

# 复杂排序逻辑
files = ['report.pdf', 'data.csv', 'notes.txt']
files.sort(key=lambda s: s.split('.')[-1])  # 按扩展名
# ['data.csv', 'notes.txt', 'report.pdf']

# 按数值部分排序(忽略前缀)
items = ['ver1.10', 'ver1.2', 'ver1.1']
items.sort(key=lambda s: [int(x) for x in s[3:].split('.')])
# ['ver1.1', 'ver1.2', 'ver1.10']

2.3 多条件组合

python 复制代码
# 先按长度,再按字母序
words = ['aa', 'b', 'aaa', 'ab', 'a']
words.sort(key=lambda s: (len(s), s))
# ['a', 'b', 'aa', 'ab', 'aaa']

# 先按绝对值,再按实际值
nums = [3, -1, 2, -2, 1]
nums.sort(key=lambda x: (abs(x), x))
# [-1, 1, -2, 2, 3]

三、多级排序

3.1 利用稳定性多次排序

Python 排序是稳定的,相等元素保持原顺序。利用这一点可实现多级排序:

python 复制代码
# 学生:姓名、年龄、成绩
students = [
    ['Alice', 20, 85],
    ['Bob', 22, 85],
    ['Charlie', 20, 92],
    ['David', 22, 78]
]

# 先按二级排序键(年龄)
students.sort(key=lambda s: s[1])
# 再按一级排序键(成绩)
students.sort(key=lambda s: s[2], reverse=True)
# 结果:
# [['Charlie', 20, 92]]      # 成绩最高
# [['Alice', 20, 85]]        # 成绩相同,年龄小的在前(稳定性)
# [['Bob', 22, 85]]          # 成绩相同,年龄大的在后
# [['David', 22, 78]]        # 成绩最低

3.2 使用元组键(推荐)

python 复制代码
students = [
    ['Alice', 20, 85],
    ['Bob', 22, 85],
    ['Charlie', 20, 92],
]

# 按成绩降序、年龄升序
students.sort(key=lambda s: (-s[2], s[1]))
# [['Charlie', 20, 92], ['Alice', 20, 85], ['Bob', 22, 85]]

# 按成绩升序、年龄升序、姓名升序
students.sort(key=lambda s: (s[2], s[1], s[0]))

优势:一次排序完成,更高效清晰。

3.3 三级及以上排序

python 复制代码
# 记录:部门、职位级别、入职时间、姓名
records = [
    ['IT', 3, 2020, 'Alice'],
    ['HR', 2, 2019, 'Bob'],
    ['IT', 3, 2021, 'Charlie'],
    ['IT', 2, 2020, 'David'],
]

# 按部门 → 级别(降序)→ 入职时间
records.sort(key=lambda r: (r[0], -r[1], r[2]))
# [['HR', 2, 2019, 'Bob'],
#  ['IT', 2, 2020, 'David'],
#  ['IT', 3, 2020, 'Alice'],
#  ['IT', 3, 2021, 'Charlie']]

四、排序稳定性

4.1 稳定排序的含义

稳定排序:相等元素的相对顺序在排序后保持不变。

python 复制代码
# 示例:按分数排序,同分保持原顺序
students = [
    ['Alice', 85],
    ['Bob', 92],
    ['Charlie', 85],
]

students.sort(key=lambda s: s[1])
# [['Alice', 85], ['Charlie', 85], ['Bob', 92]]
# Alice 原本在 Charlie 前面,排序后依然在前

4.2 实际应用场景

python 复制代码
# 任务:优先级、创建顺序
tasks = [
    ['Task C', 'high', 2],
    ['Task A', 'low', 1],
    ['Task B', 'high', 1],
]

# 先按创建时间排序
tasks.sort(key=lambda t: t[2])
# [['Task A', 'low', 1],
#  ['Task B', 'high', 1],
#  ['Task C', 'high', 2]]

# 再按优先级排序(利用稳定性)
tasks.sort(key=lambda t: t[1], reverse=True)
# [['Task B', 'high', 1],  # 同优先级,Task B 原本在前
#  ['Task C', 'high', 2],
#  ['Task A', 'low', 1]]

五、特殊场景

5.1 列表反转

python 复制代码
nums = [1, 2, 3, 4, 5]

# reverse() - 原地反转
nums.reverse()
# [5, 4, 3, 2, 1]

# 切片反转 - 创建新列表
nums = [1, 2, 3, 4, 5]
reversed_nums = nums[::-1]
# [5, 4, 3, 2, 1]
print(nums)  # [1, 2, 3, 4, 5] - 原列表不变

5.2 bisect 库:有序列表插入

bisect 是 Python 标准库,用于在已排序列表中高效查找和插入。

python 复制代码
import bisect

nums = [1, 3, 5, 7, 9]

# bisect_left:返回插入位置(相等时插入左侧)
pos = bisect.bisect_left(nums, 5)
print(pos)  # 2(索引 2,5 的位置)

# bisect_right:返回插入位置(相等时插入右侧)
pos = bisect.bisect_right(nums, 5)
print(pos)  # 3(索引 3,5 之后)

# bisect:别名,等同于 bisect_right(更常用)
pos = bisect.bisect(nums, 5)
print(pos)  # 3

插入操作

python 复制代码
nums = [1, 3, 5, 7, 9]

# insort:插入并保持有序(默认右侧)
bisect.insort(nums, 4)
# [1, 3, 4, 5, 7, 9]

# insort_left:插入到相等元素左侧
bisect.insort_left(nums, 5)
# [1, 3, 4, 5, 5, 7, 9]

# insort_right:插入到相等元素右侧
bisect.insort_right(nums, 5)
# [1, 3, 4, 5, 5, 5, 7, 9]
函数 作用 相等元素位置
bisect 查找插入位置 右侧
bisect_left 查找插入位置 左侧
bisect_right 查找插入位置 右侧
insort 插入并保持有序 右侧
insort_left 插入并保持有序 左侧
insort_right 插入并保持有序 右侧

注意bisectbisect_right 的别名,insortinsort_right 的别名,两者更常用。
时间复杂度:查找 O(log n),插入 O(n)(需要移动元素)


六、性能分析

6.1 算法:Timsort

Python 使用 Timsort 算法(结合归并排序和插入排序):

特性 说明
时间复杂度 O(n log n) 最坏/平均
空间复杂度 O(n) 额外空间
稳定性 稳定排序
适应性 对部分有序数据效率高(接近 O(n))

6.2 性能对比

python 复制代码
import timeit

TEST_SORT = "nums = list(range(1000000, 0, -1)); nums.sort()"
TEST_SORTED = "sorted(list(range(1000000, 0, -1)))"
TEST_REVERSE = "nums = list(range(1000000)); nums.reverse()"
操作 时间复杂度 空间复杂度 说明
list.sort() O(n log n) O(1) 原地排序
sorted(list) O(n log n) O(n) 创建副本,占用更多内存
list.reverse() O(n) O(1) 原地反转
切片 [::-1] O(n) O(n) 创建新列表
bisect.insort() O(n) O(1) 插入(查找 O(log n))
bisect.bisect() O(log n) O(1) 仅查找位置

6.3 性能建议

场景 推荐方法 原因
原列表可修改 list.sort() 节省内存
需保留原列表 sorted(list) 不破坏原数据
已排序列表插入元素 bisect.insort() O(n) vs O(n log n)
只需要反向 list.reverse() O(n) 原地操作

七、最佳实践

7.1 选择排序方法

python 复制代码
# 场景 1:需要修改原列表
nums = [3, 1, 2]
nums.sort()  # 推荐

# 场景 2:需要保留原列表
nums = [3, 1, 2]
sorted_nums = sorted(nums)  # 推荐

# 场景 3:链式操作
nums = [3, 1, 2]
result = sorted(nums)[:3]  # sorted 支持链式

# 场景 4:只检查排序,不实际排序
nums = [1, 2, 3]
all(nums[i] <= nums[i+1] for i in range(len(nums)-1))  # True

7.2 常见错误

python 复制代码
# 错误 1:忽略 sort() 的返回值
nums = [3, 1, 2]
sorted_nums = nums.sort()  # sorted_nums 是 None!
# 正确
nums.sort()
sorted_nums = nums

# 错误 2:修改排序后再排序
nums = [3, 1, 2]
nums.sort().reverse()  # AttributeError: 'NoneType'
# 正确
nums.sort(reverse=True)

# 错误 3:对不兼容类型排序
mixed = [1, 'a', 2]
mixed.sort()  # TypeError

7.3 代码风格建议

原则 好的写法 不好的写法
原地排序 nums.sort() nums = sorted(nums)
保留原值 sorted_nums = sorted(nums) nums_copy = nums[:]; nums_copy.sort()
多级排序 sort(key=lambda x: (-x[0], x[1])) 两次 sort 调用
反转 nums.reverse() nums = nums[::-1](当不需要保留原值)

八、总结

方面 要点
sort() 原地排序,返回 None,修改原列表
sorted() 返回新列表,原列表不变,支持链式操作
key 参数 指定比较键,支持 lambda 自定义逻辑
稳定性 Python 排序稳定,可用于多级排序
算法 Timsort,O(n log n),稳定且高效
最佳实践 原地用 sort(),保留原值用 sorted()
相关推荐
wuhen_n3 小时前
JavaScript内置数据结构
开发语言·前端·javascript·数据结构
AIFarmer3 小时前
在EV3上运行Python语言——无线编程
python·ev3
不会代码的小测试3 小时前
UI自动化-POM封装
开发语言·python·selenium·自动化
2401_841495643 小时前
【LeetCode刷题】二叉树的层序遍历
数据结构·python·算法·leetcode·二叉树··队列
roman_日积跬步-终至千里3 小时前
【Java并发】Java 线程池实战:警惕使用CompletableFuture.supplyAsync
java·开发语言·网络
lsx2024063 小时前
C++ 基本的输入输出
开发语言
ZH15455891313 小时前
Flutter for OpenHarmony Python学习助手实战:GUI桌面应用开发的实现
python·学习·flutter
B站计算机毕业设计超人3 小时前
计算机毕业设计Hadoop+Spark+Hive招聘推荐系统 招聘大数据分析 大数据毕业设计(源码+文档+PPT+ 讲解)
大数据·hive·hadoop·python·spark·毕业设计·课程设计
B站计算机毕业设计超人3 小时前
计算机毕业设计hadoop+spark+hive交通拥堵预测 交通流量预测 智慧城市交通大数据 交通客流量分析(源码+LW文档+PPT+讲解视频)
大数据·hive·hadoop·python·spark·毕业设计·课程设计