您的位置:首页 > 产品设计 > UI/UE

基础排序算法之快速排序(Quick Sort)

2013-09-03 15:57 477 查看

基础排序算法之快速排序(Quick Sort)

快速排序(Quick Sort)同样是使用了分治法的思想,相比于其他的排序方法,它所用到的空间更少,因为其可以实现原地排序。同时如果随机选取中心枢(pivot),它也是一个随机算法。最重要的是,快速排序(Quick sort)的算法分析的过程非常给力。

本文首先描述问题,再说明快速排序(Quick Sort)的基本思路并给出伪代码,之后贴出自己的Python代码。在验证完算法的正确性之后,给出如何选择好的中心枢(pivot)的方法,即随机快速排序(Randomized Quick sort),并贴代码。最后进行算法复杂度分析。

问题描述

问题描述和其他排序算法一样,输入一组未排序的数组,如左边的数组,通过快速排序算法的计算,输出一组正确排序的数组,如右边的数组。

View Code
import random

def quick_sort(datalist,l,r):
if l<r-1:
q=partition_first(datalist,l,r)
datalist=quick_sort(datalist,l,q)
datalist=quick_sort(datalist,q+1,r)
return datalist
else:
return datalist

def partition_first(datalist,l,r):
p=datalist[l]
i=l+1
for j in range(l+1,r):
if datalist[j]<p:
datalist[i],datalist[j]=datalist[j],datalist[i]
i=i+1
datalist[l],datalist[i-1]=datalist[i-1],datalist[l]
return i-1

验证算法的正确性

用数学归纳法来检验算法的正确性:

P(N)=快速排序(Quick sort)正确排序长度为N的数组。

Claim:无论选择什么p,在N>=1情况下,P(N)总能正确。

证明:

第一步:对于N=1时,返回该值。第一步完成。

第二步:第二步中只需要证明对于固定的n,如果∀k<n时,P(k)成立,那么P(n)也成立。

View Code
import random
def partition_random(datalist,l,r):
index=random.randint(l,r-1)
datalist[l],datalist[index]=datalist[index],datalist[l]
p=datalist[l]
i=l+1
for j in range(l+1,r):
if datalist[j]<p:
datalist[i],datalist[j]=datalist[j],datalist[i]
i=i+1
datalist[l],datalist[i-1]=datalist[i-1],datalist[l]
return i-1

算法分析

首先,我们先有如下定义:

输入数组的长度为定值N;

样本空间(Sample Space) Ω为在快速排序中选择中心枢(pivot)元素的所有可能性集合,其中每一个可能性其实就是一个p值的序列。

定义一个随即变量(Random Variable) C:对于∀σ∈Ω,C(σ)为在某个可能的p值序列,即某一σ情况下,输入元素相互比较的总次数。

为什么要设置这样一个随机变量?因为算法的运行时间其实主要取决于Partition函数中元素间比较的次数。所以要计算出快速排序(Quick sort)的时间复杂度,也就是要算出该随机变量C的期望值E(C)。

我们假设zi在一组数中,为第i小的数,如下图所示



我们令xij为在某一个p值序列下,zi和zj相互比较的次数之和。那么在执行快速排序(Quick sort)的时候,任意两个元素的比较次数(xij)为多少次?0或1。因为任意两个元素能够比较的前提必须是其中某一个元素被选为中心轴元素(pivot)。不管是两个元素位于p值的同边或异边都将不会在发生比较事件(Event)。

因为 C(σ)=所有输入元素相互比较的次数;xij(σ)=任意两个元素相互比较的次数

所以


根据期望的线性特性:


得出:



因为:



假定i<j,p[zi,zj发生相互比较的事件]=2/(j-i+1)。(之前已经说过两个数发生比较事件的情况只会在这两个数被选为pivot的时候发生,所以概率为头尾选中的次数除以i,j之间元素的个数)



对于i值而言,并不会超过n种情况,而对于某一固定的i值,有



所以:



可以看出,后半项是一个调和级数,所以最后:


E[C]=O(nlgn) QED!

参考:算法导论以及Tim Roughgarden的讲义
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: