Python实现十大经典排序算法

代码最后面会给出完整版,或者可以从我的Githubfork,想看动图的同学可以去这里看看;

小结:

  1. 运行方式,将最后面的代码copy出去,直接python sort.py运行即可;
  2. 代码中的健壮性没有太多处理,直接使用的同学还要检查检查;
  3. 对于希尔排序,gap的选择至关重要,需要结合实际情况更改;
  4. 在我的测试中,由于待排序数组很小,长度仅为10,且最大值为10,因此计数排序是最快的,实际情况中往往不是这样;
  5. 堆排序没来得及实现,是的,就是懒了;
  6. 关键在于理解算法的思路,至于实现只是将思路以合理的方式落地而已;
  7. 推荐大家到上面那个链接去看动图,确实更好理解,不过读读代码也不错,是吧;
  8. 分治法被使用的很多,事实上我不太清楚它背后的数学原理是什么,以及为什么分治法可以降低时间复杂度,有同学直到麻烦评论区告诉我一下哈,多谢;

运行图

由于数组小,且范围在1到10之间,这其实对于计数排序这种非比较类算法是比较友好的,因为没有多大的空间压力,因此计数排序速度第一很容易理解,而之所以选择、插入比希尔归并要快,主要还是因为问题规模本身太小,而我的分治法的实现是基于递归,因此看不出分治法的优势,事实上如果对超大的数组进行排序的话,这个区别会体现出来;

完整代码

可以看到,全部代码不包括测试代码总共才170行,这还包括了空行和函数名等等,所以本身算法实现是很简单的,大家还是要把注意力放在思路上;

  1. import sys,random,time
  2. def bubble(list_):
  3. running = True
  4. while running:
  5. have_change = False
  6. for i in range(len(list_)-1):
  7. if list_[i]>list_[i+1]:
  8. list_[i],list_[i+1] = list_[i+1],list_[i]
  9. have_change = True
  10. if not have_change:
  11. break
  12. return list_
  13. def select(list_):
  14. for i in range(len(list_)-1):
  15. min_idx = i
  16. for j in range(i,len(list_)):
  17. if list_[min_idx]>list_[j]:
  18. min_idx = j
  19. list_[i],list_[min_idx] = list_[min_idx],list_[i]
  20. return list_
  21. def insert(list_):
  22. for i in range(1,len(list_)):
  23. idx = i
  24. for j in range(i):
  25. if list_[j]>list_[idx]:
  26. idx = j
  27. break
  28. if idx != i:
  29. tmp = list_[i]
  30. list_[idx+1:i+1] = list_[idx:i]
  31. list_[idx] = tmp
  32. return list_
  33. def shell(list_,gap=None):
  34. '''
  35. gap的选择对结果影响很大,是个难题,希尔本人推荐是len/2
  36. 这个gap其实是间隙,也就是间隔多少个元素取一组的元素
  37. 例如对于[1,2,3,4,5,6,7,8,9,10]
  38. 当gap为len/2也就是5时,每一组的元素都是间隔5个的元素组成,也就是1和6,2和7,3和8等等
  39. '''
  40. len_ = len(list_)
  41. gap = int(len_/2) if not gap else gap
  42. while gap >= 1:
  43. for i in range(gap):
  44. list_[i:len_:gap] = insert(list_[i:len_:gap])
  45. gap = int(gap/2)
  46. return list_
  47. def merge(list_):
  48. '''
  49. 归并排序的递归实现
  50. 思路:将数据划分到每两个为一组为止,将这两个排序后范围,2个包含2个元素的组继续排序为1个4个元素的组,
  51. 直到回溯到整个序列,此时其实是由两个有序子序列组成的,典型的递归问题
  52. '''
  53. if len(list_)<=1:
  54. return list_
  55. if len(list_)==2:
  56. return list_ if list_[0]<=list_[1] else list_[::-1]
  57. len_ = len(list_)
  58. left = merge(list_[:int(len_/2)])
  59. right = merge(list_[int(len_/2):])
  60. tmp = []
  61. left_idx,right_idx = 0,0
  62. while len(tmp)<len(list_):
  63. if left[left_idx]<=right[right_idx]:
  64. tmp.append(left[left_idx])
  65. left_idx+=1
  66. if left_idx==len(left):
  67. tmp += right[right_idx:]
  68. break
  69. else:
  70. tmp.append(right[right_idx])
  71. right_idx+=1
  72. if right_idx==len(right):
  73. tmp += left[left_idx:]
  74. break
  75. return tmp
  76. def quick(list_):
  77. '''
  78. 快速排序:基于分治法,选定某个元素为基准,对剩余元素放置到基准的左侧和右侧,递归这个过程
  79. '''
  80. if len(list_)<=1:
  81. return list_
  82. if len(list_)==2:
  83. return list_ if list_[0]<=list_[1] else list_[::-1]
  84. base_idx = int(len(list_)/2)
  85. base = list_[base_idx]
  86. left = []
  87. right = []
  88. for i in range(len(list_)):
  89. if i != base_idx:
  90. if list_[i] <= base:
  91. left.append(list_[i])
  92. else:
  93. right.append(list_[i])
  94. return quick(left)+[base]+quick(right)
  95. def count(list_):
  96. '''
  97. 需要元素都是整型
  98. '''
  99. min_,max_ = list_[0],list_[0]
  100. for i in range(1,len(list_)):
  101. if list_[i]<min_:
  102. min_ = list_[i]
  103. if list_[i]>max_:
  104. max_ = list_[i]
  105. count_list = [0]*(max_-min_+1)
  106. for item in list_:
  107. count_list[item-min_] += 1
  108. list_ = []
  109. for i in range(len(count_list)):
  110. for j in range(count_list[i]):
  111. list_.append(i+min_)
  112. return list_
  113. def heap(list_):
  114. '''
  115. '''
  116. pass
  117. def bucket(list_):
  118. '''
  119. 每个桶使用选择排序,分桶方式为最大值除以5,也就是分为5个桶
  120. 桶排序的速度取决于分桶的方式
  121. '''
  122. bucket = [[],[],[],[],[]] # 注意长度为5
  123. max_ = list_[0]
  124. for item in list_[1:]:
  125. if item > max_:
  126. max_ = item
  127. gap = max_/5 # 对应bucket的长度
  128. for item in list_:
  129. bucket[int((item-1)/gap)].append(item)
  130. for i in range(len(bucket)):
  131. bucket[i] = select(bucket[i])
  132. list_ = []
  133. for item in bucket:
  134. list_ += item
  135. return list_
  136. def radix(list_):
  137. '''
  138. 基数排序:对数值的不同位数分别进行排序,比如先从个位开始,然后十位,百位,以此类推;
  139. 注意此处代码是假设待排序数值都是整型
  140. '''
  141. max_ = list_[0]
  142. for item in list_[1:]:
  143. if item > max_:
  144. max_ = item
  145. max_radix = len(str(max_))
  146. radix_list = [[],[],[],[],[],[],[],[],[],[]] # 对应每个位上可能的9个数字
  147. cur_radix = 0
  148. while cur_radix<max_radix:
  149. base = 10**cur_radix
  150. for item in list_:
  151. radix_list[int(item/base)%10].append(item)
  152. list_ = []
  153. for item in radix_list:
  154. list_ += item
  155. radix_list = [[],[],[],[],[],[],[],[],[]] # 对应每个位上可能的9个数字
  156. cur_radix += 1
  157. return list_
  158. def test(name,sort_func,times,info,idea,*param):
  159. list_ = [1,2,3,4,5,6,7,8,9,10]
  160. print(name+' Sort:')
  161. print('\t'+info)
  162. print('\t'+idea)
  163. print('\tTimes: '+str(times))
  164. start_time = time.time()
  165. for i in range(times):
  166. random.shuffle(list_)
  167. #print('\tInput: '+str(list_))
  168. list_ = sort_func(list_) if len(param)<=0 else sort_func(list_,param[0])
  169. #print('\tOutput: '+str(list_))
  170. #print('\t'+str(list_))
  171. print('\tCost time: '+str(time.time()-start_time))
  172. if __name__ == "__main__":
  173. test('Bubble',bubble,100000,'O(n^2), O(1), 稳定, 比较排序','思路: 循环的从头向后遍历,直到没有需要交换位置的两个元素为止')
  174. test('Select',select,100000,'O(n^2), O(1), 不稳定, 比较排序','思路: 从头到尾依次将后续序列中最小的数字放到当前位置')
  175. test('Insert',insert,100000,'O(n^2), O(1), 稳定, 比较排序','思路: 从头到尾将每个元素插入到前面的已排序序列中合适的位置,插入后后面的元素都向后移动')
  176. test('Shell(gap=len/2)',shell,100000,'O(nlogn), O(1), 不稳定, 比较排序','思路: 将序列根据gap分组,并不断细分直到只有1,每个组使用直接插入排序,有点分治法的意思,gap的选择是个难题,通常默认为len/2')
  177. test('Shell(gap=3)',shell,100000,'O(nlogn), O(1), 不稳定, 比较排序','思路: 将序列根据gap分组,并不断细分直到只有1,每个组使用直接插入排序,有点分治法的意思,gap的选择是个难题,通常默认为len/2',3)
  178. test('Shell(gap=2)',shell,100000,'O(nlogn), O(1), 不稳定, 比较排序','思路: 将序列根据gap分组,并不断细分直到只有1,每个组使用直接插入排序,有点分治法的意思,gap的选择是个难题,通常默认为len/2',2)
  179. test('Merge',merge,100000,'O(nlogn), O(n), 稳定, 比较排序','思路: 基于分治法进行归并操作,既然是分治法,那么用递归解决是最简单的实现')
  180. test('Quick',quick,100000,'O(nlogn), O(logn), 不稳定, 比较排序','思路: 同样基于分治法,通过指定某个元素为基准,小于基准的放到左边序列,大于的放到右边,递归的使左右序列有序即可')
  181. # test('Heap',heap,100000,'O(nlogn), O(1), 不稳定, 比较排序','思路: 利用堆的性质构建完全二叉树')
  182. test('Count',count,100000,'O(n+k), O(k), 稳定, 非比较排序','思路: 构造数组用于存储待排序数组中各个元素的个数,元素值作为新数组的下标')
  183. test('Bucket',bucket,100000,'O(n+k), O(n+k), 稳定, 非比较排序','思路: 将元素根据某种规则映射到N个桶中,对每个桶进行排序后,将各个桶内元素依次读出来即可')
  184. test('Radix',radix,100000,'O(n*k), O(n+k), 稳定, 非比较排序','思路: 针对各个元素的某一位依次进行排序,直到最高位为止')
  185. # print(heap([4,6,8,3,5,10,9,2,1,7]))

最后

大家可以到我的Github上看看有没有其他需要的东西,目前主要是自己做的机器学习项目、Python各种脚本工具、有意思的小项目以及Follow的大佬、Fork的项目等:

https://github.com/NemoHoHaloAi

python实现十大经典排序算法的更多相关文章

  1. 用Python实现十大经典排序算法-插入、选择、快速、冒泡、归并等

    本文来用图文的方式详细讲解了Python十大经典排序算法 —— 插入排序.选择排序.快速排序.冒泡排序.归并排序.希尔排序.插入排序.桶排序.基数排序.计数排序算法,想要学习的你们,继续阅读下去吧,如 ...

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

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

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

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

  4. python基础__十大经典排序算法

    用Python实现十大经典排序算法! 排序算法是<数据结构与算法>中最基本的算法之一.排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大, ...

  5. 十大经典排序算法(python实现)(原创)

    个人最喜欢的排序方法是非比较类的计数排序,简单粗暴.专治花里胡哨!!! 使用场景: 1,空间复杂度 越低越好.n值较大: 堆排序 O(nlog2n) O(1) 2,无空间复杂度要求.n值较大: 桶排序 ...

  6. 十大经典排序算法最强总结(含Java、Python码实现)

    引言 所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作.排序算法,就是如何使得记录按照要求排列的方法.排序算法在很多领域得到相当地重视,尤其是在大量数据的处理方面 ...

  7. 十大经典排序算法+sort排序

    本文转自:十大经典排序算法,其中有动图+代码详解,本文简单介绍+个人理解. 排序算法 经典的算法问题,也是面试过程中经常被问到的问题.排序算法简单分类如下: 这些排序算法的时间复杂度等参数如下: 其中 ...

  8. 十大经典排序算法的 JavaScript 实现

    计算机领域的都多少掌握一点算法知识,其中排序算法是<数据结构与算法>中最基本的算法之一.排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大 ...

  9. JavaScript 数据结构与算法之美 - 十大经典排序算法汇总(图文并茂)

    1. 前言 算法为王. 想学好前端,先练好内功,内功不行,就算招式练的再花哨,终究成不了高手:只有内功深厚者,前端之路才会走得更远. 笔者写的 JavaScript 数据结构与算法之美 系列用的语言是 ...

随机推荐

  1. 成长日记(2) Java面向对象

    本篇主要是记录自己在学习路上的笔记,如果有哪里记错了请大家直接指出 面向对象的概念 *人为抽象的一种编程模型 *面向过程 代码集中 难以维护 *类:对事物 算法 逻辑 概念等的抽象 理解成 模板 图纸 ...

  2. 【译】使用FormData对象

    系列文章说明 原文 FormData对象能让你生成一系列用于XMLHttpRequest发送的键值对.它主要的目的在于发送表单数据,但也能独立用于传输有键形式的数据.其传输的数据格式和表单使用subm ...

  3. 网页程序迁移至微信小程序web-view详解

    小程序现在越来越流行,但是公司的很多项目都是用网页写的,小程序语法不兼容原生网页,使得旧有项目迁移至小程序代价很高: 小程序之前开放了webview功能,可以说是网页应用的一大福音了,但是微信的web ...

  4. 浏览器渲染流程&Composite(渲染层合并)简单总结

    梳理浏览器渲染流程 首先简单了解一下浏览器请求.加载.渲染一个页面的大致过程: DNS 查询 TCP 连接 HTTP 请求即响应 服务器响应 客户端渲染 这里主要将客户端渲染展开梳理一下,从浏览器器内 ...

  5. webapck之多页面打包(常见)

    webpack多入口打包 let path = require('path'); elt HtmlWebpackPlugin = require('html-webpack-plugin'); mod ...

  6. 前端开发--vue开发部分报错指南

    前期开发过程中 [Vue warn]: Error in render: "TypeError: Cannot read property '0' of undefined". 解 ...

  7. 微信APP生命周期、页面生命周期

    目录 小程序的启动流程 app生命周期 页面的生命周期 页面的生命周期(图) 小程序的启动流程 我们画一个图来表示一下,整个小程序的启动流程,我们就知道了: app生命周期 执行App()函数也就是注 ...

  8. XCTF---easyjni的WriteUp

    一.题目来源     题目来源:XCTF的mobile区的easyjni题目.     题目下载地址:题目链接地址 二.解题过程     1.下载好题目后,安装到夜神模拟器中,发现有一个输入框和一个按 ...

  9. 对两个有序数组重新去重合并排序js实现

    这里主要是要利用两个数组有序这个条件,所以只需两个指针分别指向两个数组,当其中一个小于另外一个就移动该指针,反之则移动另外一个指针,如果相等则均向后移动. 结束条件是,当任意一个数组的指针移到末尾则跳 ...

  10. 编译putty 源码去掉 Are you sure you want to close this session? 提示

    0, 为什么要编译 putty ?在关闭窗口的时候,会弹出一个 Are you sure you want to close this session?要把这个去掉.当然也可以用 OD 之类的来修改. ...