快速排序通过不断将数列分段,使得较小的数在左边的序列,较大的数在右边的序列,不断重复此过程实现排序效果。通过设置两个哨兵不断的找两个序列的较小数,较大数,并把左右的数据互换,实现对数据从粗到细的排序。
算法如下:
快速排序排序 从大到小
1. 先让从最右边的哨兵开始出发往左移动,直到找到一个小于 A[base] 的数,或者碰到左边的哨兵
2. 再从最左边的哨兵开始出发往右移动,直到找到一个大于 A[base] 的数,或者碰到右边的哨兵
3. 如果没有相遇,这将两个哨兵所在的元素交换,使得较小的元素分到了左边,较大的元素分到了右边
4. 当两个哨兵相遇,则结束循环,把序列分成两个部分,即 低端序列(都是较小元素) 和 高端序列(都是较大元素)
5. 递归,分别对 低端序列 和 高端序列 进行同样的过程
贴代码:
1 def quicksort_rec(A,lft=None,rgt=None): 2 3 if lft == None or rgt == None: 4 lft, rgt = 0, len(A)-1 5 if lft >= rgt: 6 return 7 8 i = lft # 序列最左边的哨兵 9 j = rgt # 序列最右边的哨兵 10 base = lft # 基准数的索引 11 while i != j: 12 while A[j] >= A[base] and i < j: # 先从右往左找 13 j -= 1 14 while A[i] <= A[base] and i < j: 15 i += 1 16 if i < j: # 没有相遇:交换 17 A[i], A[j] = A[j], A[i] 18 19 A[base], A[i] = A[i], A[base] # 基准数归位, 索引 i 为序列正中 20 quicksort_rec(A, lft, i-1) # 递归处理左边序列 21 quicksort_rec(A, i+1, rgt) # 递归处理右边序列
很短对不对,下面是运行结果:
A = [6,1,2,7,9,3,4,2,5,10,8,1] quicksort_rec(A) print A >>> [1, 1, 2, 2, 3, 4, 5, 6, 7, 8, 9, 10]
另一种更简洁的实现方式:
1 # 分离数列seq为低端序列和高端序列 2 def partition(seq): 3 pi, seq = seq[0], seq[1:] # 选择数列中第0个数据为基准元素 4 lo = [x for x in seq if x <= pi] # 选出seq中较小元素 5 hi = [x for x in seq if x > pi] # 选出seq中较大元素 6 return lo,pi,hi 7 8 9 # 快速排序法 10 def quicksort(seq): 11 if len(seq)<=1: return seq 12 lo, pi, hi = partition(seq) 13 return quicksort(lo) + [pi] + quicksort(hi) 14 15 # 测试 16 seq = [1,2,4,6,3,7,5,9,0,5,7] 17 print quicksort(seq) 18 19 >>> [0, 1, 2, 3, 4, 5, 5, 6, 7, 7, 9]
利用上面的函数partition,可以使用二分法查找第k个最小的元素(不排序)
1 # 选择数组中第k小元素 2 def select(seq, k): 3 lo, pi, hi = partition(seq) # [<= pi], pi, [> pi] 4 m = len(lo) 5 if m == k: return pi # 找到第k最小值 6 elif m < k: 7 return select(hi,k-m-1) 8 else: 9 return select(lo,k)
调用方法:
# 原数组:seq = [1,2,4,6,3,7,5,9,0,5,7] # 排序后:[0, 1, 2, 3, 4, 5, 5, 6, 7, 7, 9] print select(seq,6) >>> 5