对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 插入并保持有序 右侧

注意 :bisect 是 bisect_right 的别名,insort 是 insort_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()
相关推荐
mmmmath_32 小时前
LeetCode.199.二叉树的右视图
数据结构·leetcode
专注仿真2 小时前
引擎扩展性与集成设计深度剖析:从 14 个扩展点到 DIS→HLA 演进之路
开发语言·算法·仿真引擎·推演引擎
Best-Wishes3 小时前
科来网络分析系统(技术交流版)使用说明书
开发语言·junit·php
代码不停3 小时前
自动化测试(java)
java·开发语言·selenium·自动化
Smoothcloud润云4 小时前
PyTorch大模型权重加载与启动耗时优化实战:定位磁盘、内存与显存瓶颈
人工智能·pytorch·python·深度学习·gpu算力
databook4 小时前
从循环到向量化:NumPy提速的7个关键思维
python·数据分析·numpy
棉猴4 小时前
玩游戏学Python1-Python和pgzero库的安装
python·pygame·玩游戏·pgzero·pgzrun
诺伦5 小时前
GEO优化数据实证:78%引用流向官网的机制拆解与小品牌三步管线实战教程 | RiseClaw玄策
python·seo·geo·内容营销·ai搜索
oooost5 小时前
pytorch学习笔记1
python·学习方法
鬼手点金5 小时前
opencode-rules 插件
java·开发语言·前端·人工智能·chrome·git·github