快速排序

速排序由于排序效率在同为O(N*logN)的几种排序方法中效率较高,因此经常被采用,再加上快速排序思想----分治法也确实实用,因此很多软件公司的笔试面试,包括像腾讯,微软等知名IT公司都喜欢考这个,还有大大小的程序方面的考试如软考,考研中也常常出现快速排序的身影。

总的说来,要直接默写出快速排序还是有一定难度的,因为本人就自己的理解对快速排序作了下白话解释,希望对大家理解有帮助,达到快速排序,快速搞定。

 

快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序。它采用了一种分治的策略,通常称其为分治法(Divide-and-ConquerMethod)。

该方法的基本思想是:

1.先从数列中取出一个数作为基准数。

2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。

3.再对左右区间重复第二步,直到各区间只有一个数。

 

虽然快速排序称为分治法,但分治法这三个字显然无法很好的概括快速排序的全部步骤。因此我的对快速排序作了进一步的说明:挖坑填数+分治法:

import java.util.Arrays;

/**
 * 第1次排序:[9, 6, 12, 34, 45, 79, 65]
 * 第2次排序:[6, 9, 12, 34, 45, 79, 65]
 * 第3次排序:[6, 9, 12, 34, 45, 79, 65]
 * 第4次排序:[6, 9, 12, 34, 45, 65, 79]
 */
public class QuickSort {
    public static int count = 0;

    public static void main(String[] args) {
        int array[] = {34, 65, 12, 45, 6, 79, 9};
        quickSort(array);
    }

    public static void quickSort(int[] array) {
        if (array != null) {
            quickSort(array, 0, array.length - 1);
        }
    }

    private static void quickSort(int[] array, int beg, int end) {
        if (beg >= end || array == null)
            return;
        int p = partition(array, beg, end);
//        System.out.println("第一次排序");
        System.out.print("第" + (++count) + "次排序:");
        System.out.print(Arrays.toString(array));
        System.out.println();
        quickSort(array, beg, p - 1);
        quickSort(array, p + 1, end);
    }

    private static int partition(int[] array, int beg, int end) {
        int pivot = array[beg];
        while (beg < end) {
            while (beg < end && array[end] >= pivot)
                end--;
            if (beg < end)
                array[beg++] = array[end];
            while (beg < end && array[beg] <= pivot)
                beg++;
            if (beg < end)
                array[end--] = array[beg];
        }
        array[beg] = pivot;
        return beg;
    }

}
//  快排空间复杂度O(log2(n))   归并O(n)    
//
//        心情不稳当,快些选一对好友来聊天-----------快速,希尔,简单选择,堆排序---------------不稳当
//
//          快些以 nlog2(n)归队------------------------快速,希尔,归并,堆排序----------------------时间负载度 nlog2(n)
//
//          
//
//          直接插容易插成O(n),起泡起的好编程O(n)------------------容易插,起的好,都是初始化序列已经有序

 

 

 

下面以中间为基排序

这个时候要注意,比较条件是大于或者小于,不能有等于,不然程序会出错

import java.util.Arrays;
import java.util.Comparator;


/**
 * 快速排序。
 * <p>
 * 第1次排序:[34, 9, 12, 6, 45, 79, 65]
 * 第2次排序:[6, 9, 12, 34, 45, 79, 65]
 * 第3次排序:[6, 9, 12, 34, 45, 79, 65]
 * 第4次排序:[6, 9, 12, 34, 45, 65, 79]
 * 第5次排序:[6, 9, 12, 34, 45, 65, 79]
 * 最终结果
 * [6, 9, 12, 34, 45, 65, 79]
 */

/**
 * 第1次排序:[34, 9, 12, 6, 45, 79, 65]
 * 第2次排序:[6, 9, 12, 34, 45, 79, 65]
 * 第3次排序:[6, 9, 12, 34, 45, 79, 65]
 * 第4次排序:[6, 9, 12, 34, 45, 65, 79]
 * 第5次排序:[6, 9, 12, 34, 45, 65, 79]
 * 最终结果
 * [6, 9, 12, 34, 45, 65, 79]
 */

/**
 * 分治和递归,以中间为准基数,分割数组为两部分,
 *      如果左边的index0指向数据小于准基数,则满足条件(左边的小于准基数),
 *      下标增加一(index0++),用下一个数据和准基数对比,如果满足,再看一下个数据。
 *      如果右边的数据大于准基数,则满足条件(右边的数据大于准基数),
 *      下边减一(index1--),用上一个数据和准基数进行对比。。。
 */

public class QuickSort2 {
    public static int count = 0;

    public static void QuickSort2(int[] inputs, Comparator<Integer> cp) {

        sort(inputs, 0, inputs.length - 1, cp);
    }

    /**
     * 快速排序算法,结果是从小到大。
     *
     * @param inputs 待排序对象数组。
     * @param low    首
     * @param high   尾
     */
    private static void sort(int[] inputs, int low, int high,
                             Comparator<Integer> cp) {
        int index0 = low;
        int index1 = high;
        int mid;
        if (high > low) {
            mid = inputs[(low + high) / 2];
            while (index0 <= index1) {
                while ((index0 < high) && (cp.compare(inputs[index0], mid) < 0)) {
                    ++index0;
                }
                while ((index1 > low) && (cp.compare(inputs[index1], mid) > 0)) {
                    --index1;
                }
                if (index0 <= index1) {
                    swap(inputs, index0, index1);
                    ++index0;
                    --index1;
                }
            }
            System.out.print("第" + (++count) + "次排序:");
            System.out.print(Arrays.toString(inputs));
            System.out.println();
            if (low < index1) {
                sort(inputs, low, index1, cp);
            }
            if (index0 < high) {
                sort(inputs, index0, high, cp);
            }
        }
    }

    /**
     * 交换。
     *
     * @param objs
     * @param i
     * @param j
     */
    private static void swap(int[] objs, int i, int j) {
        int T;
        T = objs[i];
        objs[i] = objs[j];
        objs[j] = T;
    }

    public static void main(String[] args) {
        int array[] = {34, 65, 12, 45, 6, 79, 9};
        Comparator<Integer> integerComparator = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1 - o2;
            }
        };
        QuickSort2(array, integerComparator);
        System.out.println("最终结果");
        System.out.println(Arrays.toString(array));


    }
}

 

 

import java.util.Arrays;


/**
 * 快速排序。
 * 第1次排序:[34, 9, 12, 6, 45, 79, 65]
 * 第2次排序:[6, 9, 12, 34, 45, 79, 65]
 * 第3次排序:[6, 9, 12, 34, 45, 79, 65]
 * 第4次排序:[6, 9, 12, 34, 45, 65, 79]
 * 第5次排序:[6, 9, 12, 34, 45, 65, 79]
 * [6, 9, 12, 34, 45, 65, 79]
 */
public class QuickSort3 {
    public static int count = 0;

    public static void QuickSort3(int[] inputs) {
        sort(inputs, 0, inputs.length - 1);
    }

    /**
     * 快速排序算法,结果是从小到大。
     *
     * @param inputs 待排序对象数组。
     * @param low    首
     * @param high   尾
     */
    private static void sort(int[] inputs, int low, int high) {
        int index0 = low;
        int index1 = high;
        int mid;
        if(count==3){
            System.out.println(111);
        }
        if (high > low) {
            mid = inputs[(low + high) / 2];
            while (index0 <= index1) {
                while ((index0 < high) && ((inputs[index0] - mid) < 0)) {
                    ++index0;
                }
                while ((index1 > low) && ((inputs[index1] - mid) > 0)) {
                    --index1;
                }
                if (index0 <= index1) {
                    swap(inputs, index0, index1);
                    ++index0;
                    --index1;
                }
            }
            System.out.print("第" + (++count) + "次排序:");

            System.out.print(Arrays.toString(inputs));
            System.out.println();
            if (low < index1) {
                sort(inputs, low, index1);
            }
            if (index0 < high) {
                sort(inputs, index0, high);
            }
        }
    }

    /**
     * 交换。
     *
     * @param objs
     * @param i
     * @param j
     */
    private static void swap(int[] objs, int i, int j) {
        int T;
        T = objs[i];
        objs[i] = objs[j];
        objs[j] = T;
    }

    public static void main(String[] args) {
        int array[] = {34, 65, 12, 45, 6, 79, 9};

        QuickSort3(array);
        System.out.println(Arrays.toString(array));

    }
}


这个问题其实也没有多么复杂,但是网上这部分内容不多,故总结一下最优与最差比较次数。


n个元素线性表快速排序,最好情况下比较次数是多少?


参照严书的方法,以第一位作为标杆。


①考虑第一趟排序,无论怎样也要有n-1次比较次数;


②如果此时能把数据分成两部分,前一部分与后一部分元素个数相近,那样就是最优的。


  例如,4 1 2 3 5 6 7,经过一趟排序,变成 1 2 3 4 5 6 7 。也就是说,以4为标杆,一趟后分成了两部分,这两部分个数相同或相差  1,那么快排会很优。


  于是,可以想到,最优时,n个数,第一趟分成前⌊(n-1)/2⌋,后⌈(n-1)/2⌉两组,每组也是按照最优的分,设最优是an,于是有:


   an = a⌊(n-1/2)⌋+a⌈(n-1/2)⌉ + n - 1


  比如,n=7时,最优情况就是  a7=a3+a3+6 ,a3=a1+a1+2 ,而显然a1=0。 


   于是a3=2,a7=10。


 


   举 例  4 1 3 2 6 5 7 。第一次4为标杆,一趟后为 2 1 34 6 5 7 


   第二趟两边分别以2,6为标杆,这样最好,因为是均分了。


   问题,n=8时,最好排序次数?


   a8=7+a4+a3,a3算的2,a4=3+a1+a2,显然a2=1,于是a4=4,故a8=13


   因此,n=8时,最好情况下比较次数是13。


  举例,4 1 3 2 6 5 7 8  可以数一下


   对于别的情况,参照这个思路即可轻松求比较次数以及举例。


 


n个元素线性表快速排序,最坏情况下比较次数是多少?


    这个就容易多了,因为顺序或者逆序时最坏的。


    故比较次数,1+2+3……+ n-1 = n(n-1)/2

 

 

posted @ 2018-07-17 01:50  鹏鹏进阶  阅读(776)  评论(0编辑  收藏  举报