【算法】排序算法之快排

想法

乱序数组中找任一个元素,做 pivot。

比 pivot小的,放到pivot左侧,反之放右侧。

以 pivot 为中心,对其左右两个子数组,递归执行前两步,直到最后子数组长度为1结束。

 

细节

怎么完成第二步的?

具体方法是,数组两端各有一个指针low,high,都往中间扫,各自指向不符合的元素(low指向大于pivot的元素,high指向小于等于pivot的元素),此时若low<high,则将两元素对换,否则让 high/low 指向的元素与 pivot 所在元素互换位置,完成。(扫描结束时low与high相邻low在high右侧, high指向的元素是<=pivot的,low指向元素是大于pivot的。假设此时pivot在low的左侧,如果low指向的元素与pivot对调,pivot左侧就不是全小于等于pivot,所以pivot与high相换,如果此时pivot在low的右侧,那么同理,应该与low对调)

也就是先把除了 pivot 以外的数组分为两边,一边所有元素小于另一边的所有元素。最后把 pivot ,放到中间。

可以看到第二步就是把数组遍历了一次,另外,还可以看到此番“交换”,只用了三个指针的额外空间。

 

时间复杂度:

递归结束的条件是所有子数组长度为1。比如长度为 10,如果 7 个元素大于 pivot,2 个元素小于 pivot,那么拖后腿的部分就可能是 7 。所以最理想情况是,每轮都对半。每一轮都会去掉1个pivot元素,列下公式如下。

n + (n/2+n/2 - 1) + (n/4+n/4+n/4+n/4 - 2) + ....+ (1+1+..+1 - log2n) = O(log2n 个 n 的相加) = O(nlog2n)

1         2                         3                                         最后一轮

所以最好的时间复杂度就是 O(nlog2n)。

最坏的情况每一轮,都是 0:n-1的局面。

n + n-1 +  n-2 +  .... + 1 =  O(n2)

 

平均情况是一个把所有情况的复杂度相加除以情况数算出来的,比较复杂,这里直接上结论就是最好情况的 O(nlog2n)

 

空间复杂度

前面已经分析过每一轮都是3个指针,所以最好情况一共log2n轮, 3*log2n =  O(log2n),平均情况下也是

 

稳定的排序算法

假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。

在快排中稳不稳这就要看运气了,比如 3,5(1),5(2),2,6 ,

如果以3为 pivot,第一轮排序后,2,3,5(2),5(1),6

如果以5(2) 为 pivot,第二轮排序后,2,3,5(2),5(1),6

如果以 5(1) 为 pivot,第三轮排序后 ,2,3,5(2),5(1),6

看运气的稳就是不稳。

 

上代码:

代码方便起见,将pivot指向数组首个元素,这样每次扫描结束后high与pivot对换。

public class QuickSort {
    public static void main(String[] args) {
        int[] elements = new int[]{1,3,4,2,7,6,5};
        qsort(elements, 0, elements.length-1);
        for (int element : elements) {
            System.out.print(element + " ");
        }
    }

    private static void qsort(int[] elements, int start, int end){
        if(end <= start){
            return;
        }
        int pivot = start;
        int low = start;
        int high = end;
        while(low<high){
            while(low < end && elements[low]<=elements[pivot]) {
                low++;
            }
            while(high > start && elements[high]>elements[pivot]){
                high --;
            }
            if(low<high) {
                int tmp = elements[low];
                elements[low] = elements[high];
                elements[high] = tmp;
            }
        }
        int tmp = elements[high];
        elements[high] = elements[pivot];
        elements[pivot] = tmp;
        qsort(elements, start, high-1);
        qsort(elements, high+1, end);
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值