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

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

        为什么说它实用性最强呢?因为快速排序的平均性能非常好,虽然它的最坏运行时间为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]已排序。(这里没有合并过程,和合并排序有很大不同。关于合并排序


快速排序代码如下:

/**
     * 快速排序
     * @param A 目标数组
     * @param p 左标记位
     * @param r 右标记位
     */
    public 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 切割位
     */
    public 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在一个包含了八个元素数组上的操作。


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



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


但是!!但是其实有个坑


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

/**
     * 快速排序  来自数据结构(严蔚敏)
     * @param A 目标数组
     * @param left 左标记位
     * @param right 右标记位
     */
    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相等。

在不申请额外空间的情况下,竟然直接赋值,我一开始看到这个的时候是吃惊的。真相其实是用一个key(第一个基准值)来存一个数据,这样之后的数组里就一直会有一个空的位置用来赋值,最后等主要工作完成,再将key赋值给最终空的位置,就这样实现了一波交换。(相当的巧妙啊!!,_(:з」∠)_我是服的)

上面有所有方法的单元测试:https://github.com/qjkobe/IntroductionToAlgorithms


如果有啥问题记得跟我说哈


原文:http://blog.csdn.net/qj30212/article/details/52474837

我略微修改了一下代码和描述







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值