写在前面

排序是查找是算法中最重要的两个概念,我们大多数情况下都在进行查找和排序。科学家们穷尽努力,想使得排序和查找能够更加快速。本篇文章用Python实现十大排序算法。

干货儿

排序算法从不同维度可以分为好多类别,从其排序思想(排序思想一般决定了其时间复杂度的量级)来看,主要可以分为四类:

  • 双层循环比较排序:平方级排序
  • 分治策略比较排序:对数级排序
  • 另辟蹊径的非比较方式排序:线性级排序
  • 笑死人不偿命的其它排序:有着天马行空的时间复杂度,难以描述。
平方级排序
  • 冒泡排序

    1. 从数组的第一个元素开始,比较当前元素和下一个元素,如果当前元素大于下一个元素,交换两元素位置。
    2. 接着从第二个元素开始,重复第一步,直到当前元素为最后一个元素。此时最后一个元素为最大元素。未排序数组为除最后一个元素之外的其它元素。
    3. 对未排序数组不断重复以上步骤,直到未排序数组为空。
    def bubble_sort(arr):
    length = len(arr)
    for i in range(length):
    for j in range(length-i-1):
    if arr[j] > arr[j+1]:
    arr[j], arr[j+1] = arr[j+1], arr[j]
    return arr
  • 选择排序

    1. 选取数组中的最小元素,和数组中的第一个元素交换位置
    2. 选取数组中除第一个元素外剩余元素的最小元素,和数组中的第二个元素交换位置。
    3. 不断重复以上步骤,直到当前选取的元素为数组中最后一个元素。
    def select_sort(arr):
    length = len(arr)
    for i in range(length):
    min_ix = i
    for j in range(i, length):
    if arr[j] < arr[min_ix]:
    min_ix = j
    arr[min_ix], arr[i] = arr[i], arr[min_ix]
    return arr
  • 插入排序

    1. 从数组的第一个元素开始,不断比较当前元素和前一个元素。如果当前元素比前一个元素小,那么就将当前元素插入到前一个元素的前面(即两者交换位置)
    2. 从第二个元素开始,不断重复以上步骤,直到所有元素全部经历上述步骤。
    def insert_sort(arr):
    length = len(arr)
    for i in range(length):
    for j in range(i, 0, -1):
    if arr[j] < arr[j-1]:
    arr[j], arr[j-1] = arr[j-1], arr[j]
    return arr
对数级排序
  • 希尔排序

    1. 选择一个增量值k,分别将数组中索引以k为间隔的元素放在同一个数组中。
    2. 将增量值缩小为原增量值的1/2,然后重复步骤1。
    3. 直到增量值为1,使用插入排序对已经部分有序的数组进行排序。
    def shell_sort(arr):
    n = len(arr)
    gap = int(n/2)
    while gap > 0:
    for i in range(gap,n):
    temp = arr[i]
    j = i
    while j >= gap and arr[j-gap] >temp:
    arr[j] = arr[j-gap]
    j -= gap
    arr[j] = temp
    gap = int(gap/2)
    return arr
  • 归并排序

    1. 以数组中间元素为界,将数组分为等长的两个数组(可能不等长,和数组长度的奇偶性有关)。
    2. 对所有数组执行步骤1
    3. 不断重复以上步骤,直到将数组分割为多个包含单个元素的数组。
    4. 将以上数组两两合并,并排序,此时为多个包含有序的两个元素的数组(可能包含单个元素,跟数组长度的奇偶性有关)。
    5. 重复步骤4,直到将所有数组合并为一个数组
    def merge(left, right):
    i = j = 0
    res = []
    while i < len(left) and j < len(right):
    if left[i] < right[j]:
    res.append(left[i])
    i += 1
    else:
    res.append(right[j])
    j += 1
    if i == len(left):
    res.extend(right[j:])
    else:
    res.extend(left[i:])
    return res def merge_sort(arr):
    if len(arr) <= 1:
    return arr
    length = len(arr)
    i = int(length / 2)
    left = merge_sort(arr[:i])
    right = merge_sort(arr[i:])
    return merge(left, right)
  • 快速排序

    1. 挑选一个元素为基准
    2. 比基准大的元素作为一个数组,比基准小或者等于基准的元素作为一个数组。
    3. 对新分割的数组,不断重复以上步骤,直到分割后的数组只含有1个或者0个元素
    4. 递归地合并以上数组为有序数组,合并方式为:[小于等于基准的元素]+[基准]+[大于基准的元素]
    def fast_sort(arr):
    if len(arr) <= 1:
    return arr
    pivot = arr.pop()
    left = [i for i in arr if i <= pivot]
    right = [i for i in arr if i > pivot]
    return fast_sort(left) + [pivot] + fast_sort(right)

    以上算法需要额外的空间,如果我们将小于等于基准的元素不断置于基准元素之前,大于基准的元素置于基准元素之后,那么就可以实现不需要额外空间的就地排序。

    def fast_sort_on_extra_spacing(arr):
    l = 0
    h = len(arr)-1 def partition(arr, l, h):
    pivot = arr[h]
    for i in range(l, h):
    if arr[i] <= pivot:
    arr[l], arr[i] = arr[i], arr[l]
    l += 1
    arr[h], arr[l] = arr[l], arr[h]
    return l def fast_sort(arr, l, h):
    if l < h:
    pivot = partition(arr, l, h)
    fast_sort(arr, l, pivot-1)
    fast_sort(arr, pivot+1, h)
    return arr
    return fast_sort(arr, l, h)
  • 堆排序

    1. 先对待排序数组构造大根堆
    2. 将大根堆第一个元素和最后一个元素交换位置。此时最后一个元素为最大元素,待排序数组为除最后一个元素之外的所有元素。
    3. 对待排序数组不断重复以上步骤,直到待排序数组中只有一个元素。
    def heapify(arr, n, i):
    # build a max root heap
    max_ix = i
    left_i = 2 * i + 1
    right_i = 2 * i + 2 if left_i < n and arr[max_ix] < arr[left_i]:
    max_ix = left_i
    if right_i < n and arr[max_ix] < arr[right_i]:
    max_ix = right_i
    if max_ix != i:
    arr[max_ix], arr[i] = arr[i], arr[max_ix]
    heapify(arr, n, max_ix) def heap_sort(arr):
    for i in range(n-1, -1, -1):
    heapify(arr, n, i) for i in range(n-1, 0, -1):
    arr[i], arr[0] = arr[0], arr[i]
    heapify(arr, i, 0)
    return arr
线性级排序

此排序方法只适用于数组元素全部为整数的情景。

  • 计数排序

    1. 找出待排序数组中最大的元素,构造一个长度为此元素值的计数数组。
    2. 遍历待排序数组元素,以当前元素为索引,将计数数组中的对应值加1.
    3. 此时计数数组中的索引为待排序数组中的元素,值为出现的次数。将计数数组中所有值非0的元素索引根据其出现次数串联起来。
    def count_sort(arr):
    min_ix, max_ix = min(arr), max(arr)
    bucket = [0 for _ in range(max_ix+1)]
    for i in arr:
    bucket[i] += 1
    return sum([[i] * bucket[i] for i in range(len(bucket)) if bucket[i] != 0], [])
  • 桶排序

    1. 设置固定数量的桶(这是个技术活儿).
    2. 将待排序数组中的元素放入对应的桶中(对应关系也是个技术活儿,下面的例子中采用整除)
    3. 将非空桶中的元素串联起来。
    def bucket_sort(arr):
    min_ix, max_ix = min(arr), max(arr)
    bucket_range = (max_ix - min_ix) / len(arr)
    # +1 avoid for that max_ix - min_ix will raise a IndexError
    temp_bucket = [[] for i in range(len(arr) + 1)]
    for i in arr:
    temp_bucket[int((i-min_ix)//bucket_range)].append(i)
    return sum(temp_bucket, [])
  • 基数排序

    1. 找出待排序数组中最大元素的位数。将所有元素补足此位数,补足方式为前面补0。
    2. 从最低位到最高位,进行多轮数组排序。
    def radix_sort(arr):
    max_value = max(arr)
    num_digits = len(str(max_value))
    for i in range(num_digits):
    bucket = [[] for _ in range(10)]
    for j in arr:
    bucket[j//(10**i)%10].append(j)
    arr = [j for i in bucket for j in i]
    return arr
笑死人不偿命排序
  • 睡排序

    让多个进程(线程)分别睡眠待排序数组中的元素时长,先睡醒的进程(线程),对应元素追加到结果数组中。

  • 猴子排序

    不停随机排序,然后检查是否元素全部有序。如果你是欧皇,那么你可以尝试用这个排序算法,很可能一次搞定。

排序算法复杂度、稳定性及通用性总结
算法 平均时间复杂度 最优时间复杂度 最坏时间复杂度 空间复杂度 是否原地排序 是否稳定 是否通用
冒泡排序 O(n2) O(n) O(n2) O(1)
选择排序 O(n2) O(n2) O(n2) O(1)
插入排序 O(n2) O(n) O(n2) O(1)
希尔排序 O(n logn) O(n log2n) O(n log2n) O(1)
归并排序 O(n logn) O(n logn) O(n logn) O(n)
快速排序 O(n logn) O(n logn) O(n2) O(n logn)
堆排序 O(n logn) O(n logn) O(n logn) O(1)
计数排序 O(n+k) O(n+k) O(n+k) O(k)
桶排序 O(n+k) O(n+k) O(n2) O(n+k)
基数排序 O(n*k) O(n*k) O(n*k) O(n+k)
写在最后

排序算法是算法学习中的核心。掌握排序算法及其思想是学习其它算法的基础。希望大家可以熟练掌握。欢迎关注个人博客:药少敏的博客

一篇夯实一个知识点系列--python实现十大排序算法的更多相关文章

  1. 一篇夯实一个知识点系列--python生成

    写在前面 本系列目的:一篇文章,不求鞭辟入里,但使得心应手. 迭代是数据处理的基石,在扫描内存无法装载的数据集时,我们需要一种惰性获取数据的能力(即一次获取一部分数据到内存).在Python中,具有这 ...

  2. 一篇夯实一个知识点系列--python装饰器

    写在前面 本系列目的:希望可以通过一篇文章,不望鞭辟入里,但求在工程应用中得心应手. 装饰器模式是鼎鼎大名的23种设计模式之一.装饰器模式可以在不改变原有代码结构的情况下,扩展代码功能. Python ...

  3. python实现十大核心算法(桶排没实例)

    # author:sevenduke # 2019-06-11 # 一.交换排序 # 排序算法的温故:冒泡排序 def dubblesort(arr): for i in range(0, len(a ...

  4. Python实现的选择排序算法原理与用法实例分析

    Python实现的选择排序算法原理与用法实例分析 这篇文章主要介绍了Python实现的选择排序算法,简单描述了选择排序的原理,并结合实例形式分析了Python实现与应用选择排序的具体操作技巧,需要的朋 ...

  5. 排序算法——(2)Python实现十大常用排序算法

    上期为大家讲解了排序算法常见的几个概念: 相关性:排序时是否需要比较元素 稳定性:相同元素排序后是否可能打乱 时间空间复杂度:随着元素增加时间和空间随之变化的函数 如果有遗忘的同学可以看排序算法——( ...

  6. Python实现十大经典排序算法(史上最简单)。

    十大排序算法(Python实现)一. 算法介绍及相关概念解读 算法分类十种常见排序算法可以分为两大类: 非线性时间比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn), ...

  7. Python实现十大经典排序算法(史上最简单)

    十大排序算法(Python实现)一. 算法介绍及相关概念解读 算法分类十种常见排序算法可以分为两大类: 非线性时间比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn), ...

  8. 每日一个知识点系列:volatile的可见性原理

    每日一个知识点系列的目的是针对某一个知识点进行概括性总结,可在一分钟内完成知识点的阅读理解,此处不涉及详细的原理性解读. img 看图说话 关键点1: 总线嗅探器(MESI 缓存一致性原理 ) 关键点 ...

  9. python实现十大经典排序算法

    Python实现十大经典排序算法 代码最后面会给出完整版,或者可以从我的Githubfork,想看动图的同学可以去这里看看: 小结: 运行方式,将最后面的代码copy出去,直接python sort. ...

随机推荐

  1. Burp Suite Target Module - 目标模块

    模块目的之一:获取网站分析 1.从Proxy - HTTP history界面选中需要加入Target Scope的Host 地址,右击,选中Add to Scope. 2.打开Target - Sc ...

  2. Python Ethical Hacking - BACKDOORS(7)

    Handling Errors: If the client or server crashes, the connection will be lost. Backdoor crashes if: ...

  3. vue使用select间相互绑定

    让这两个select相互绑定,让roleOptions选取值后,worklist弹出得是roleOptions值 <el-select v-model="postForm.projec ...

  4. EF批量插入太慢?那是你的姿势不对

    大概所有的程序员应该都接触过批量插入的场景,我也相信任何的程序员都能写出可正常运行的批量插入的代码.但怎样实现一个高效.快速插入的批量插入功能呢? 由于每个人的工作履历,工作年限的不同,在实现这样的一 ...

  5. Spring 与 MyBatis 事务管理源码解析

    用到mybatis便由spring和myabtis集成,SqlSessionFactoryBean(直接负责对mybatis所需环境的创建) ,配置相应的datasource到springConfig ...

  6. sublimeCLang配置报错以及sublime快捷键

    subimeClang需要手动配置我真的真的很服 记录一下满是报错的高光时刻 -------- 不过这个问题刚刚解决了 只要把所有的shared_ptr改成std::shared_ptr 就行 说白了 ...

  7. 阿里云ecs轻量级服务器node镜像部署

    这个是自带安装pm2,nginx,node,mongodb的环境的,目录在控制台有给出, server端的配置按照开发手册去操作即可. 而静态的页面.需要修改nginx的配置文件,找到nginx的ng ...

  8. PHP xml_get_error_code() 函数

    定义和用法 xml_get_error_code() 函数获取 XML 解析器错误代码.高佣联盟 www.cgewang.com 如果成功,该函数则返回错误代码.如果失败,则返回 FALSE. 语法 ...

  9. PHP mysqli_sqlstate() 函数

    返回最后一个 MySQL 操作的 SQLSTATE 错误代码: <?php 高佣联盟 www.cgewang.com // 假定数据库用户名:root,密码:123456,数据库:RUNOOB ...

  10. Spring学习总结(4)-Spring生命周期的回调

    参考文档:https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans ...