快速排序

快排的基本思想是:通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。通常可选第一个记录为基准来重新排列其余记录,另外它需要一个栈空间来实现递归。

通常用第一个记录作为基准的时候

最好情况:每次基准归位,刚好落在序列的中间,将序列均匀的划分为长度相等或相近的两个子序列。栈空间最大深度为log(n+1),1表示最外层参数进栈

时间复杂度:n·log(n)

空间复杂度:log(n)

最坏情况:初始序列已经有序或基本有序时,每趟排序之后基准落在子序列的一端,则为最坏情况。栈空间最大深度为n

时间复杂度:n^2

空间复杂度:n

数据量大且有序时,使用第一个记录为基准排序会很慢,在leetcode 215题中就体现出来了,因此需要用下面方法对最坏情况进行改进

改善基准的选取

1,随机选基准

随机选择基准可以提升最坏情况下的性能,但是在随机选择时也有最坏情况,即每次都选择了有序序列的一端,最坏时间复杂度也是O(N^2),但整体还是比上述以第一个为基准要好。

2,三者取中(a[0],a[-1],a[len(a)//2])

《严 · 数据结构》上推荐使用三者取中,可大大改善快速排序在最坏情况下的性能。

(3,BFPRT是不是也能优化快排的基准选择,如果用了BFPRT,基准每次都划分在序列中间位置,这样总的快排时间复杂度就是优化前的复杂度n·log(n),就不存在最坏O(N^2)的情况。)

改善快排的递归过程

以基准划分序列时,用两个boolean变量标记两指针向中间移动过程中是否进行过交换,若有哪一部分没有进行交换,则无需对这部分进行递归,进而提升了性能。

代码实现

import random

def partition(nums, left, right, base):
'''基准归位'''
if left == right:
return
temp = nums[base]
nums[base], nums[right] = nums[right], nums[base] # 和尾部节点交换 max_index = left
for i in range(left, right):
if nums[i] < temp:
nums[i], nums[max_index] = nums[max_index], nums[i]
max_index += 1
nums[max_index], nums[right] = nums[right], nums[max_index]
return max_index def quick_sort(nums, left, right):
'''快速排序'''
if left >= right:
return base = random.randint(left, right) # 随机选取基准
base_index = partition(nums, left, right, base) quick_sort(nums, left, base_index-1) # 递归左边
quick_sort(nums, base_index+1, right) # 递归右边 if __name__ == '__main__':
nums = [6, 1, 8, 8, 8, 2, 7, 9, 3, 8, 8, 4, 5, 10]
left, right = 0, len(nums) - 1 quick_sort(nums, left, right)
print(nums)

快速选择

和快排partition过程一致,分治过程只操作有用的一半,另一半不管。

import random

def partition(nums, left, right, base):
'''基准归位'''
if left == right:
return
temp = nums[base]
nums[base], nums[right] = nums[right], nums[base] # 和尾部节点交换 max_index = left
for i in range(left, right):
if nums[i] < temp:
nums[i], nums[max_index] = nums[max_index], nums[i]
max_index += 1
nums[max_index], nums[right] = nums[right], nums[max_index]
return max_index def quick_select(nums, left, right, K):
'''快速选择'''
if left == right: # 分治的序列仅剩一个元素,那么就是它了
return nums[left] base = random.randint(left, right) # 随机选取基准
base_index = partition(nums, left, right, base) if base_index == K:
return nums[base_index]
elif base_index > K:
return quick_select(nums, left, base_index-1, K) # 递归左边
else:
return quick_select(nums, base_index+1, right, K) # 递归右边 if __name__ == '__main__':
nums = [6, 1, 8, 8, 8, 2, 7, 9, 3, 8, 8, 4, 5, 10]
nums = list(set(nums))
print(nums) left, right = 0, len(nums) - 1
K = 2 # 第K大 ans = quick_select(nums, left, right, right-K+1) # 等于N-K+1小,10-2+1=9
print(ans)

最新文章

  1. as3的操作符重载
  2. 活动组件(五):一个activity的例子
  3. ASP.NET MVC 上传大文件时404
  4. POJ 2528 Mayor&#39;s posters (线段树区间更新+离散化)
  5. mysql命令具体解释
  6. Python3.5 入门学习记录——变量类型
  7. 【转】CoreData以及MagicalRecord (一)
  8. Labview学习之程序Web发布
  9. ural 1837. Isenbaev&#39;s Number bfs
  10. 2017-3-2 C#基础 结构体
  11. Java初学习-常见单词
  12. Pandas系列(三)-缺失值处理
  13. 安装 yaml-cpp,MP4V2
  14. 自动化测试基础篇--Selenium判断元素是够存在
  15. 火狐对SVG的兼容性
  16. Hybrid App 开发初探:使用 WebView 装载页面
  17. nginx 在ubuntu上使用笔记(绑定域名)
  18. git中的重要指令
  19. JBPM学习第6篇:通过Git导入项目
  20. Bootstrap Div 居中的方法

热门文章

  1. java中通过jacob调用dts进行数据导入导出
  2. PHP获取网站中各文章的第一张图片的代码示例
  3. BottomNavigationView(底部导航)
  4. 【DM8168学习笔记6】学习思路整理
  5. LA3211 Now or later
  6. istio1.1(openshift) 流量路由
  7. 《2018年云上挖矿态势分析报告》发布,非Web类应用安全风险需重点关注
  8. kindle电子书下载网站收藏
  9. localStorage对象简单应用 - - 访问次数
  10. JS---案例:滚动条