快速排序
快速排序名字可不是盖的,很多程序语言标准库实现的内置排序都要它的身影, 我们就直奔主题吧。和归并排序一样,快排也是一种分而治之(divide
and
conquer)的策略。归并排序把数组递归成只有单个元素的数组,之后再不断两两合并,最后得到一个有序的数组。这里的递归基本条件就是只包含一个元素的数组,当数组只包含一个元素的时候,我们可以认为它本来就是有序的(当然空数组也不用排序).
快排的工作过程其实比较简单,三步走:
1.选择基准值 pivot 将数组分成两个子数组:小于基准值的元素和大于基准值的元素。这个过程称之为 partition
2.对这两个子数组进行快速排序
3.合并结果
根据这个想法我们可以快速写出快排的代码,简直就是在翻译上边的描述:
# -*- coding:utf-8 -*-
def quicksort(array):
if len(array) < 2:
return array
else:
pivot_index = 0
pivot = array[pivot_index]
#构造一个小于基准值的元素数组
less_port = [i for i in array[pivot_index+1:] if i <= pivot]
#构造一个大于基准值的元素数组
great_sort = [i for i in array[pivot_index+1:] if i > pivot]
return quicksort(less_port) + [pivot] + quicksort(great_sort)
def test_quicksort():
import random
seq = list(range(10))
random.shuffle(seq)
assert quicksort(seq) == sorted(seq)
是不是很简单,下次面试官让你手写快排你再写不出来就有点不太合适啦。当然这个实现也有两个不好的地方:
1.第一是它需要额外的存储空间,我们想实现inplace原地排序
2.第二是它的partition操作每次都要两次遍历整个数组,我们想改善一下
这里我们来优化一下它,实现inplace排序并且改善下partition操作.
# -*- coding:utf-8 -*-
def quicksort(array):
if len(array) < 2:
return array
else:
pivot_index = 0
pivot = array[pivot_index]
less_port = [i for i in array[pivot_index+1:] if i <= pivot]
great_sort = [i for i in array[pivot_index+1:] if i > pivot]
return quicksort(less_port) + [pivot] + quicksort(great_sort)
'''
方法实现:
第一个元素作为 pivot主元,
将比主元值小的元素放在主元左边
将比主元值大的元素放在主元右边
'''
def partition(array,beg,end):
pivot_index = beg
pivot = array[pivot_index]
left = pivot_index + 1
right = end - 1
while True:
while left <= right and array[left] < pivot:
left += 1
while right >= left and array[right] >= pivot:
right -= 1
if left > right:
break
else:
array[left],array[right] = array[right],array[left]
array[pivot_index],array[right] = array[right],array[pivot_index]
return right
def test_partition():
l = [4,1,2,8]
assert partition(l,0,len(l)) == 2
l = [1,2,3,4]
assert partition(l,0,len(l)) == 0
l = [4,3,2,1]
assert partition(l,0,len(l)) == 3
def quicksort_inplace(array,beg,end):
if beg < end:
pivot = partition(array,beg,end)
quicksort_inplace(array,beg,pivot)
quicksort_inplace(array,pivot+1,end)
def test_quicksort_inplace():
import random
seq = list(range(10))
random.shuffle(seq)
print(seq)
quicksort_inplace(seq,0,len(seq))
print(seq)