关于快速排序

    快速排序是基于partition过程的排序方法,时间复杂度O(nlogn),是几种O(logn)的排序算法中常系数最小的。

    partition顾名思义是划分。选定一个元素a,把所有小于等于a的元素放到a的左边,大于a的元素放到a的右边,这里a左边和右边的区域不需要有序。

    经典快速排序算法是每次选定最末尾的元素x,partition之后,x左边的元素都小于等于x,右边的元素都大于x,也就是说x就位了。之后对x左边和右边的两段分别递归进行排序过程,让所有元素就位,整个数组完成排序。

    经典快速排序的问题在于每次只能让一个元素就位。可以用荷兰国旗问题的思路进行改进。

---------------------------------------------------------------------------------------------------------------

    荷兰国旗问题:给定一系列随机排列0、1、2,要求把所有的0归到左边、1归到中间、2归到右边。

    核心思路还是每一步缩小问题规模。用left、right两个指针表示已经左右两端完成的区域small和big,left和right之间即为所有与目标值相等的元素要放的区域,cur指针指向当前遍历到的元素。一开始,left位于第一个元素的左边,right在最后一个元素的右边(即small和big区的大小都为0),cur指向第一个元素。每次迭代,将cur指向的元素x与给定值a比较,x<a,将x与left+1位置的元素交换,一个small区元素就位,将left向右移一格,small区域向中间扩展一格;同理,若x>a,将x与right-1位置元素交换,一个big区元素就位,将right向左移一格,big区域向中间扩展一格;若x=a,不用动。这样,每次迭代,问题缩小至在数组size-1规模上进行,big和small区域逐渐向中间扩展,直到cur与right相遇,此时所有小于a的元素在左边,大于a的在右边,等于a的在中间,划分完成。

-----------------------------------------------------------------------------------------------------------------

     应用荷兰国旗问题的思路,可以把经典快速排序算法的partition过程改为选定一个元素,将所有与它相等的值放在中间,比它小的在右边,比它大的在左边,然后对两边的部分递归进行排序过程,直到所有元素有序。这样每次可以把等于某个值所有的元素归位,减小时间复杂度的常系数项,提高排序的效率。

    快速排序的另一个问题是样本中元素的排列对排序效率的影响较大。每次划分之后的big和small区规模越接近就越快,当每次都均分时,只需递归log2n层。反之两者规模相差越大就越慢,最坏情况下,每次划分之后变成一个元素和一个区域,退化为冒泡排序,O(n^2)。

    对此,可以每次随机选择目标元素a,由于每次选择不是确定的,时间复杂度就成了一个期望值O(nlogn),消除原序列的排列对排序效率的影响。

    

猜你喜欢

转载自blog.csdn.net/daniel_2046/article/details/80679943