排序算法-快速排序(Quick Sort)
Posted 詩和遠方
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了排序算法-快速排序(Quick Sort)相关的知识,希望对你有一定的参考价值。
关于Quick Sort的介绍网上资料非常多,本文仅是我重新学习此算法时的笔记,如有纰漏,还请网友指出。
快排算法利用分治法(divide and conquer)思想,每次将数组中的一个基准元素(pivot)放在其应该在的位置,所有比基准小的数放在其左边,比基准大的元素放在其右边。然后将左右两个子序列进行递归处理。算法的关键是用基准将数组拆分成两个子序列,我们暂且将这个过程称之为partition,具体有几种不同的实现方法。这里均用python实现。
partition函数
实现一
def partition(ls, left, right):
pivot = ls[left] # first element as pivot
i, j = left, right
while i < j: # check j first, the order is important
while ls[j] >= pivot and i < j:
j -= 1
while ls[i] <= pivot and i < j:
i += 1
if i < j:
ls[i], ls[j] = ls[j], ls[i]
ls[i], ls[left] = ls[left], ls[i]
return i
以第一个元素作为基准,维护左右两个指针,从后往前遍历数组S,找到第一个比基准数小的元素,从前往后遍历数组,找到第一个比基准数小的元素,交换这两个数,重复以上过程,直到指针下标相等,最后再将基准元素与指针所在元素交换。
每一次交换如下:
实现二
def partition(ls, left, right):
pivot = ls[left] # first element as pivot, treat ls[left] as an hole
i, j = left, right
while i < j:
while ls[j] >= pivot and i < j:
j -= 1
if i < j: # find ls[j] less than pivot, put it to the hole ls[i], then move i forward
ls[i] = ls[j]
i += 1
while ls[i] <= pivot and i < j:
i += 1
if i < j: # find ls[i] greater than pivot, put it to the hole ls[j], then move j backward
ls[j] = ls[i]
j -= 1
ls[i] = pivot # if i == j, put pivot back to hole
return i
以上代码看上去有点奇怪,每次只是赋值,并没有像第一种方法一样进行交换操作,实际可以这样理解:移出pivot,ls[0]的值已重复多余,就当它是一个空白/洞,等着别的值来覆盖/填充,然后右边找到第一个比pivot小的元素ls[j],将它填充到ls[0],此时轮到ls[j]的值重复多余……,最后用pivot的值覆盖ls[i]。
第一轮交换:
实现三
def partition(ls, left, right):
pivot = ls[left] # first element as pivot
i, j = left, right
while i < j: # check j first, the order is important
while ls[j] >= pivot and i < j:
j -= 1
if i < j: # find a[j] < pivot, swap them, then move i forward
ls[i], ls[j] = ls[j], ls[i]
i += 1
while ls[i] <= pivot and i < j:
i += 1
if i < j: # find a[i] > pivot, swap them, then move j backward
ls[i], ls[j] = ls[j], ls[i]
j -= 1
return i
以上代码与实现二有点相似,唯一的差别在于每次都交换,所以不用像实现二一样做最后一次将pivot归位的操作。
第一轮交换:
主函数
def quick_sort(ls, left, right):
if left < right:
i = partition(ls, left, right)
quick_sort(ls, left, i - 1)
quick_sort(ls, i + 1, right)
if __name__ == "__main__":
ls = [85, 24, 63, 45, 17, 31, 96, 50, 85]
quick_sort(ls, 0, len(ls) - 1)
print(ls)
代码关键点说明
- partition函数是核心,其中第一版最简洁,交换次数也最少
- 其实以上三种实现,差别并不大,这里啰嗦的将他们都列出来,只是希望通过比较实现细节,从而能更深刻地理解快速排序算法
- 以上算法均以第一个元素作为pivot,需要先移动右边的指针,因为最后一次交换是pivot与ls[i]的交换,而pivot位于最左边,所以ls[i]不能大于pivot,否则交换之后ls[i]在最左边,却比pivot大,这显然是不正确的。反之如果算法将最后一个元素作为pivot,则需要先移动左边的指针。
以上是关于排序算法-快速排序(Quick Sort)的主要内容,如果未能解决你的问题,请参考以下文章
python 学习笔记 -- 数据结构与算法 快速排序 Quick Sort