快速排序

微困啊。。贴完这篇赶快睡觉去。。困了

OK, Let’s get started…

快速排序和上一篇归并排序一样也是使用DIVIDE AND CONQUER的策略。但不同之处是快排是就地排序的,也就是说在每一时刻只有常数个元素会存储在原序列之外,对于空间复杂度来说比Merge Sort要好。

同样的对于基于分治法策略的算法来说都有三个基本步骤:

DIVIDE:

快排的分治步骤是通过一个Partition的子程序完成的,它基于一个随机选择的pivot元素将原序列分成两个部分,其中左半边的元素均小于pivot,而右半边均大于,pivot中间位置。

CONQUER:

与归并排序一样,CONQUER的步骤都是递归的调用自身来处理两个子序列。直到满足递归终止条件,即处理到单个元素,那意味着已经是排序好的。

COMBINE:

快排没有合并步骤,因为是原地排序,不需要像Merge Sort一样把子序列合并成最终序列。

和归并排序做比较对于理解快速排序是很有帮助的,之前谈到过归并排序在递归后存在一个回代过程,递归到处理2个单元素子序列后才从递归树的底部开始向上执行Merge,直到回到顶部。而快速排序则是从递归树的顶部开始逐步排序,当到达底部后意味着整个序列已经排好序了。

其实贴个图更好描述它的过程。。不过今天太困了。。睡了先。。

代码如下,依然是python,写起来和说话一样:


def partitionOfQuickSort(L, start, end):
    key = L[start]         
    i = start
    j = i + 1
    while j <= end:
        if L[j] <= key:    
            i = i + 1
            tmp = L[i]
            L[i] = L[j]
            L[j] = tmp
        j = j + 1
    L[start] = L[i]
    L[i] = key
    return i

def quickSort(L, start, end):
    if start < end:
        mid = partitionOfQuickSort(L, start, end)
        quickSort(L, 0, mid - 1)
        quickSort(L, mid + 1, end)
    return L

这段程序中的PARTITION步骤中,每次都是将序列中的第一个数作为主元,这样对于处理已经排好序或者反向排好序的输入,代价是很大的,因为每次划分子序列并没有显著的降低输入的规模,这种情况运行时间的递归表达式为

T(n) = T(0) + T(n – 1) + cn

cn为Partition步骤的代价

所以有T(n) = Θ(n2)   对于排序来说是苦情的表达式。。

但算法导论里有提到,可以有很多种方法改进快排,比如随机选择主元的随机化快速排序,它的时间复杂度就是nlgn。而且因为是原地排序,一般情况下均比归并排序快2到3倍。


Partion的循环不变量:

在上面贴的代码中,变量i和j各维护2个子序列,其中A[1, i]是比主元小的序列,A[i+1, j]是比主元大的序列。j向右移动,每当遇到比主元小的元素就让i向右移动,然后与A[i]进行交换,这样在迭代的过程中两个表的不断向右移动直到填满整个序列,最后让A[i]与主元交换,即完成了工作。

转载于:https://www.cnblogs.com/leavingQ/archive/2012/01/07/2315478.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值