当前位置:   article > 正文

python排序算法速度比较:快速排序,归并排序,冒泡排序

python排序算法速度比较:快速排序,归并排序,冒泡排序

 

前言

原理就不在这里说了,好多大神肯定比我这个初学者讲的好很多,推荐去B站看视频讲解,跟着手敲代码

为什么选这三个排序呢?

  • 首先快排是必须掌握的
  • 看看快排在最坏的情况下(O(n²)),且不使用辅助空间,与冒泡(O(n²))的比较
  • 由于快排是不稳定的排序算法,且平均时间复杂度为O(nlogn),那找一个时间复杂度为O(nlogn)稳定排序算法,那么就非归并排序莫属了.

 

一、快速排序,归并排序,冒泡排序比较

 

算法时间复杂度空间复杂度稳定性
平均最好最坏
冒泡排序O(n²)O(n)O(n²)O(1)稳定
快速排序O(nlogn)O(nlogn)O(n²)O(1)或O(n)不稳定
归并排序O(nlogn)O(nlogn)O(nlogn)O(n)稳定

 

二、源码

 

  • 引入库,并生成1000个随机数,然后深拷贝若干份.
  1. import random
  2. from copy import deepcopy
  3. arr0 = [random.randint(1, 100) for _ in range(1000)]
  4. # arr0 = [_ for _ in range(1000, 0, -1)]
  5. # print(arr0)
  6. for i in range(1, 11):
  7. exec(f'arr{i} = deepcopy(arr0)')

 

1.冒泡

  1. def bubble_sort(arr):
  2. for i in range(len(arr) - 1):
  3. for j in range(len(arr) - 1 - i):
  4. if arr[j] >= arr[j + 1]:
  5. arr[j], arr[j + 1] = arr[j + 1], arr[j]
  6. return arr

2.归并

  1. def merge_sort(arr):
  2. length = len(arr)
  3. if length <= 1:
  4. return arr
  5. mid = length // 2
  6. # 以下标mid为分界点,将arr的[:mid]给left,[mid:]给right
  7. left = merge_sort(arr[:mid])
  8. right = merge_sort(arr[mid:])
  9. lp = 0
  10. rp = 0
  11. res = []
  12. # 切记这里不是<=,因为数组的index一定是小于数组长度的
  13. while lp < len(left) and rp < len(right):
  14. if left[lp] <= right[rp]:
  15. res.append(left[lp])
  16. lp += 1
  17. else:
  18. res.append(right[rp])
  19. rp += 1
  20. # 这里要用extend. left,right切片后的值为一个list
  21. res.extend(left[lp:])
  22. res.extend(right[rp:])
  23. return res

3.快排

  1. # 一句话快排
  2. qs = lambda arr: arr if len(arr) <= 1 else qs([it for it in arr[1:] if it <= arr[0]]) + [arr[0]] + \
  3. qs([it for it in arr[1:] if it > arr[0]])
  4. # 空间复杂度O(1)的快排
  5. def quick_sort_O1(arr, left, right):
  6. if left >= right:
  7. return
  8. base = arr[left]
  9. lp = left
  10. rp = right
  11. while lp < rp:
  12. while lp < rp and arr[rp] >= base:
  13. rp -= 1
  14. arr[lp] = arr[rp]
  15. while lp < rp and arr[lp] < base:
  16. lp += 1
  17. arr[rp] = arr[lp]
  18. arr[lp] = base
  19. quick_sort_O1(arr, left, lp - 1)
  20. quick_sort_O1(arr, lp + 1, right)
  21. return arr
  22. # 空间复杂度O(n)的快排
  23. def quick_sort_On(arr: list):
  24. if len(arr) <= 1:
  25. return arr
  26. left = []
  27. right = []
  28. base = arr.pop(0)
  29. for it in arr:
  30. if it <= base:
  31. left.append(it)
  32. else:
  33. right.append(it)
  34. return quick_sort_On(left) + [base] + quick_sort_On(right)
  35. # 空间复杂度O(n)的快排,引入随机处理,尝试规避快排的最坏风险
  36. def quick_sort_On_random(arr: list):
  37. if len(arr) <= 1:
  38. return arr
  39. left = []
  40. right = []
  41. base = arr.pop()
  42. while arr:
  43. tmp = arr.pop()
  44. if tmp <= base:
  45. left.append(tmp)
  46. else:
  47. right.append(tmp)
  48. return quick_sort_On(left) + [base] + quick_sort_On(right)

 

三、创建长度为1000的list,在jupyter notebook上运行,观察结果

1.随机无序数组结果

  • 空间换时间的做法明显让快排效率提高了一个数量级~

2.反序数组结果 

  1. 将arr0重新赋值如下:
  2. arr0 = [_ for _ in range(1000, 0, -1)]

 

 3.正序数组结果

  1. 将arr0重新赋值如下:
  2. arr0 = [_ for _ in range(1000)]

 

4.内置函数--遥遥领先

**内置函数那么快,学啥快排(捂脸)...

随机无序数组

 反序数组

 正序结果

 


总结

先不总结了,大致情况就如上吧.希望大家看完后给些意见和建议.

不知道有什么地方没考虑进去,本来只是为了规避快排最坏情况的风险而实现的quick_sort_On_random,意外发现每次都是最快的???

 

2020-12-16:

查找了相关资料,找到了quick_sort_On_random速度最快的原因,在这里记录一下  

1.从列表的末尾(右端)弹出在CPython中需要恒定的时间,但是从左端弹出(.pop(0))需要的时间与列表的长度成正比

2.所有the_list [1:]中的元素在物理上向左移动一个位置.

3.如果需要经常删除索引位置0,那么使用collections.deque的实例要好得多. Deques支持从两端有效推送和弹出.

 

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号