Java--快速排序

        快速排序是对冒泡排序的改进,可以分单向扫描法和双向扫描法两种。

        首先看单向扫描的快速排序:

1. 选定数组的一个元素作为“主元”(也可以称为基准或枢轴)。之后扫描一趟数组,将小于或等于主元的元素放在主元的左边,大于主元的元素放在主元的右边。具体做法是:

        a.选定数组的第一个元素作为主元。

        b.定义左指针lp和右指针rp,用数组下标赋值。其中rp右侧的数据都大于主元。初始时,lp指向数组的第二个元素,rp指向数组的最后一个元素。

        c.第一趟的扫描流程为:在左指针下标小于或等于右指针下标的条件下进行循环,比较是否 左指针所指元素小于或等于主元,如果是,左指针右移一位;否则,交换两指针所指元素,并将 右指针左移一位。

        交换过程如下图所示(左指针lp所指元素大于主元,与右指针rp所指元素交换,且右指针左移一位):

        d.循环继续,比较得到此时左指针所指元素小于主元(1 < 4),左指针右移一位。

        e.再次比较得到左指针所指元素不小于主元(6 > 4),交换两指针所指元素,并将右指针左移一位。

        交换过程如下图所示:

        f.再次比较[lp]小于主元(2 < 4), 左指针右移一位。

        g.[lp]不小于主元(7 > 4),交换两指针所指元素,并将右指针左移一位。

         此时,lp == rp,仍满足左指针小于或等于右指针的条件,继续比较[lp]小于主元(3 < 4),那么左指针右移一位,此时lp > rp。

        循环结束,rp右侧的数据都大于主元,且rp所指元素小于主元,此时交换rp所指元素与主元。至此第一趟快速排序完成。

2. 此时,数组以主元为界,分为两部分,分别对两部分递归实现快速排序,即再次选取新主元进行排序。

图片描述

3. 上述递归结束的条件是:子数组中只有1个元素或0个元素。

图片描述

单向扫描的快速排序图示

        单向扫描的快速排序代码:

public class QuickSort {
    // 递归实现单向扫描的快速排序
    public void quickSort(int[] arr, int l, int r) {
        if (l < r) {
            // 进行一躺快速排序,取当前主元作为边界
            int q = pv(arr, l, r);
            // 分别扫描排序边界两侧
            quickSort(arr, l, q - 1);
            quickSort(arr, q + 1, r);
        }
    }
    
    // 实现数组的一趟单向扫描的快速排序。从l扫描到r,返回当前主元位置
    public int pv(int[] arr, int l, int r) {
        // 主元p
        int p = arr[l];
        // 扫描指针:左指针lp,右指针rp
        int lp = l + 1;
        int rp = r;
        while (lp <= rp) {
            // 如果左指针所指的数小于等于主元,左指针右移一位
            if (arr[lp] <= p) 
                lp++;
            else { // 如果大于主元,交换左右指针的数据,右指针左移一位
                swap(arr, lp, rp);
                rp--;
            }
        }
        swap(arr, l, rp);// 交换主元和指针所指的数据
        return rp;
    }

    // 实现数组中两个元素的交换
    public void swap(int[] arr, int index1, int index2) {
        int temp = arr[index1];
        arr[index1] = arr[index2];
        arr[index2] = temp;
    }
}

        再就是双向扫描的快速排序:

1. 和单向扫描法一样,双向扫描法也是选定数组的一个元素为主元,然后对于主元之外的元素,从左右两侧同时扫描。小于或等于主元的元素放在主元的左边,大于主元的元素放在主元的右边。具体做法是:

        left向右扫描的过程中,如果left所指元素小于或等于主元,则left右移一位,否则停止移动;right向左扫描的过程中,如果right所指元素大于主元成立,则right左移一位,否则停止移动。当left和right都停止移动时,如果left ≤ right,则交换两指针所指元素。

        a.选定数组的第一个元素为主元。

        b.除主元之外的元素,选定数组的第二个元素为左侧left,数组的最后一个元素为右侧right,并且同时向右 / 左扫描。

图片描述

         c.left向右扫描(移动),发现当前所指元素不小于主元(5 > 4),停止移动;right向左扫描,发现当前所指元素不大于主元(1 < 4),停止移动。此时左右两侧都停止移动,并交换两侧所指元素。

图片描述

图片描述

        d.重复c的步骤。再对[2]和[5]、[3]和[4]交换。

图片描述

        e.此时left ≤ right,left所指元素小于主元,right所指元素大于主元,所以left右移,right左移。

图片描述

        f.当前left > right,循环终止,交换right所指元素与主元。 

图片描述

        至此第一趟排序完成。 

2. 再用递归,将此时主元(right)左侧和右侧的子数组视为两个待排序的数组,再次进行排序。

         双向扫描的快速排序代码:

public class DoubleQuickSort {
    // 递归实现双向扫描的快速排序
    public void quickSort(int[] arr, int l, int r) {
        if (l < r) {
            int q = pv2(arr, l, r);
            quickSort(arr, l, q - 1);
            quickSort(arr, q + 1, r);
        }
    }

    // 一趟双向扫描的快速排序,返回当前边界
    public int pv2(int[] arr, int l, int r) {
        int p = arr[l];
        int left = l + 1;
        int right = r;
        while (left <= right) {
            while (left <= right && arr[left] <= p)
                left++;
            while (left <= right && arr[right] > p)
                right--;
            if (left < right)
                swap(arr, left, right);
        }
        swap(arr, l, right);
        return right;
    }

    // 交换数组中的两个元素
    public void swap(int[] arr, int index1, int index2) {
        int temp = arr[index1];
        arr[index1] = arr[index2];
        arr[index2] = temp;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值