对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()
相关推荐
用户8356290780511 天前
无需 Office:Python 批量转换 PPT 为图片
后端·python
markfeng81 天前
Python+Django+H5+MySQL项目搭建
python·django
GinoWi1 天前
Chapter 2 - Python中的变量和简单的数据类型
python
JordanHaidee1 天前
Python 中 `if x:` 到底在判断什么?
后端·python
ServBay1 天前
10分钟彻底终结冗长代码,Python f-string 让你重获编程自由
后端·python
闲云一鹤1 天前
Python 入门(二)- 使用 FastAPI 快速生成后端 API 接口
python·fastapi
Rockbean1 天前
用40行代码搭建自己的无服务器OCR
服务器·python·deepseek
曲幽1 天前
FastAPI + Ollama 实战:搭一个能查天气的AI助手
python·ai·lora·torch·fastapi·web·model·ollama·weatherapi
用户60648767188962 天前
国内开发者如何接入 Claude API?中转站方案实战指南(Python/Node.js 完整示例)
人工智能·python·api
只与明月听2 天前
RAG深入学习之Chunk
前端·人工智能·python