排序算法之——快速排序(Java实现)

来源:互联网 发布:水上电动滑板 淘宝 编辑:程序博客网 时间:2024/05/17 00:06

        排序算法有很多,今天我来讲一讲其中实用性最强的一种算法——快速排序。

        为什么说它实用性最强呢?因为快速排序的平均性能非常好,虽然它的最坏运行时间为O(n^2),但是平均运行时间是O(nlgn),而且里面隐含的常数因子很小。而且它是原地排序的,所谓原地排序,就是不需要开辟新的数组空间,就可以进行排序。

        快速排序基于分治模式,所谓分治模式,就是把问题拆成一个个小问题,直到问题可以解决。以下是分治过程的三个步骤:

        分解:数组A[p...r]被划分成两个子数组(可能空)A[p...q-1]和A[q+1...r],使得前者每个元素都小于等于A(q),后者中的每个元素都大于A(q)。

        解决:通过递归调用快速排序,对子数组A[p...q-1]和A[q+1...r]排序。

        合并:因为两个子数组是就地排序的,所以合并不需要操作。整个数组A[p...r]已排序。(这里没有合并过程,和合并排序有很大不同。关于合并排序)


快速排序代码如下:

    void QuickSort(int[]A, int p, int r){        if(p < r){            int q = Partition(A, p, r);            QuickSort(A, p, q - 1);            QuickSort(A, q + 1, r);        }    }


快速排序的核心是Partition过程,代码如下:

    /**对子数组A[p...r]进行就地重排     * @param A     * @param p     * @param r     * @return     */    int Partition(int[] A, int p, int r){        int x = A[r];        int i = p - 1;        for(int j = p; j < r; j++){            if(A[j] <= x){                i++;                int temp = A[i];                A[i] = A[j];                A[j] = temp;            }        }        int temp = A[i + 1];        A[i + 1] = A[r];        A[r] = temp;        return i + 1;    }

下面的图片显示了Partition在一个包含了八个元素数组上的操作。


所以说,其实数组被分成了四个部分:



以上就是快速排序的内容。比较简单,图片来自于《算法导论》


但是!!但是其实有个坑


在做阿里笔试题的时候发现了。尼玛它的快速排序怎么感觉和我的不一样。百度了一下,偶,果然不一样。。下面这个排序的思路来自数据结构(严蔚敏),代码如下:


    public void qsort(int[] A, int left, int right){        if(left < right) {            int key = A[left];            int low = left, high = right;            while (low < high) {                while (low < high && A[high] > key) {                    high--;                }                A[low] = A[high];                while (low < high && A[low] < key) {                    low++;                }                A[high] = A[low];            }            A[low] = key;            qsort(A, left, low - 1);            qsort(A, low + 1, right);        }    }

这个思路的意思是:先选定左边为基准值(你要选右边也可以,后面代码相应改一改),定义low,high,然后先从后向前找,如果找到了比基准值小的,则low下标处等于该值,否则high--,然后再从前往后找,如果找到了比基准值大的,则high下标处等于该值,否则low++,直到low和high相等。这道题令人惊奇的是它交换数据的方式:

每个值被覆盖之前。都被拿走了。首先是基准值,然后之后每个值都是先拿走,然后才可能被覆盖,最后再把基准值放到最后一个被拿走的值里。这样就实现了一波交换。牛逼啊。


两个算法大家都要知道,否则以后笔试就会和我一样坑。

如果对代码有疑惑可以看我的github源码,上面有所有方法的单元测试:https://github.com/qjkobe/IntroductionToAlgorithms


如果发现问题,请立刻告诉我。我可不想误人子弟


1 0
原创粉丝点击