不多说,直接上源码吧
# Author: Jintao Huang
# Email: hjt_study@qq.com
# Date:
# Ref: https://www.bilibili.com/video/BV16D4y1d7d1
"""排序笔记总结
排序方法 时间复杂度(最好/最坏/平均) 空间复杂度 稳定性 特点
插入排序: 适用于几乎有序
1. 直接插入 O(N) O(N^2) O(N^2) O(1) 稳定 (前有序,后无序)
2. 折半插入 O(NLogN) O(N^2) O(N^2) O(1) 稳定 搜索O(LogN), 移动O(N). (前有序,后无序)
3. 希尔 未知 O(1) 不稳定 对每个子序列进行直插排序
交换排序 每趟排序确定一个最终位置
1. 冒泡 O(N) O(N^2) O(N^2) O(1) 稳定 从前往后冒泡. (后有序,前无序)
2. 快速 O(NLogN) O(N^2) O(NLogN) O(LogN)-O(N) 不稳定
选择排序 每趟排序确定一个最终位置
1. 简单选择 O(N^2) O(N^2) O(N^2) O(1) 不稳定 (前有序,后无序)
2. 堆 O(NLogN) O(NLogN) O(NLogN) O(1) 不稳定 非递减用大根堆. (前有序,后无序)
建堆、删除(下滤). 插入(上滤)
二路归并排序 O(NLogN) O(NLogN) O(NLogN) O(N) 稳定
复杂度与初始状态相关:插排 * 2, 冒泡, 快速
前有序,后无序: 直接插入, 折半插入; 简单选择, 堆
后有序,前无序: 冒泡
"""
from typing import Any, Callable, List
import time
from copy import copy
import random
def get_runtime(func, *args, **kwargs):
t = time.time()
result = func(*args, **kwargs)
print(time.time() - t)
return result
def shuffle_arr(arr: List[Any]) -> List[Any]:
"""打乱数组"""
arr = copy(arr)
random.shuffle(arr)
return arr
def test_sort(func):
# test time
import random
a = list(range(5000))
random.seed(0)
a = shuffle_arr(a)
result = get_runtime(func, a)
result2 = get_runtime(func, a, key=lambda x: x % 10)
print(result[:10])
print(result2[:10])
def test_sort_std(func):
# test time
import random
a = list(range(5000))
random.seed(0)
a = shuffle_arr(a)
get_runtime(func, a)
print(a[:10])
print("sorted")
test_sort(sorted)
# sorted
# 0.0
# 0.0009980201721191406
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# [3550, 1500, 3310, 530, 2970, 490, 850, 650, 3690, 3480]
def bubble(arr: List[Any], lo: int, hi: int) -> None:
"""将arr[low:high]中最大的元素冒泡到arr[high - 1]处. 比较次数: hi - 1 - lo
Ot(N) Os(1)
"""
for i in range(lo, hi - 1):
# 前比后大则置换,等于则不置换(for stable)
if arr[i] > arr[i + 1]:
arr[i], arr[i + 1] = arr[i + 1], arr[i]
def bubble_sort(arr: List[Any], *, key: Callable[[Any], Any] = None) -> List[Any]:
"""冒泡排序 stable. 从前往后冒泡. Ot(N^2) Os(N)
:param arr: const
:param key: func
:return:
"""
# 防止重复计算key造成的性能下降、引入i为了stable
arr = [(key(x), i, x) for i, x in enumerate(arr)] if key is not None else copy(arr)
for n in reversed(range(2, len(arr) + 1)): # bubble()结束位置[len, 2], 每轮比较的次数[len - 1, 1]
bubble(arr, 0, n) # 最大的往后扔
return [item[2] for item in arr] if key is not None else arr
def bubble_sort_std(arr: List[Any]) -> None:
"""冒泡排序 stable. 从前往后冒泡. Ot(N^2) Os(1)"""
# 防止重复计算key造成的性能下降、引入i为了stable
for n in reversed(range(2, len(arr) + 1)): # bubble()结束位置[len, 2], 每轮比较的次数[len - 1, 1]
bubble(arr, 0, n) # 最大的往后扔
print("bubble_sort")
test_sort(bubble_sort)
print("-----------------------")
test_sort_std(bubble_sort_std)
# bubble_sort
# 1.6645495891571045
# 1.8520421981811523
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# [3550, 1500, 3310, 530, 2970, 490, 850, 650, 3690, 3480]
# -----------------------
# 1.6525754928588867
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
"""
https://www.bilibili.com/video/BV16D4y1d7d1
tim排序:用于python的sorted()和list.sort()中
是 二分插入排序(二分查找+) + 归并排序. Ot(NLogN) Os(N)
基于一个事实:
现实生活中,大多数真实的数据集中,已经有很多元素是排好序的
术语:
run(分区):一组数据的集合(严格的单调递增或递减)
1. 元素个数 < 64_python(或32_java),使用二分插入排序
2. > 64,使用tim排序
(tim排序自己内部做的判断)
tim排序的步骤:
1. 先遍历全表,查找严格递增/递减的区间(run)(长度的讲究),
严格递减的部分反转得到递增
2. 分区根据一定规则合并。维持合并效率
"""
def tim_sort():