python 冒泡排序 选择排序 插入排序 快速排序 归并排序 算法源码

不多说,直接上源码吧

# 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():
    
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值