快速排序( ̄o ̄) . z Z

前言

每件事的最后都会是好事 如果不是好事 说明还没到最后

经典快排

经典快排的思想其实就是:选择一个基准数,将大于这个基准数的数放在基准数的右边,小于等于的放在左边。然后再分别在这两个区域中选择基准数,再将这两个区域分别分为大于和小于等于两个区域,直到最后排好序。

  1. 首先我们将数组中的第一个数设为temp,也就是我们的基准数。将数组最后一个数设为j。
  2. 从j开始,一个个依次向前查找,找到第一个小于temp的数,停止。如图,第一个数3就小于基准数4,所以此时停下。
  3. 接着从第一个数依次向后查找,即图中的i。当找到第一个大于temp的数后,停下。
  4. 将i和j的数进行交换。
  5. 继续从j开始查找下一个小于temp的数。重复上面的 2 3 4。
  6. 当i和j相遇后,结束这次遍历。将i和temp进行交换后结束。
    这里写图片描述
    这样,我们一次操作就完成了。接下来,在进行递归,依次对两个区域进行上面的操作。最后整个数组将有序。

Code

 public void quicksort (int[] s,int left,int right){
        if (left>right){
            return;
        }
        int i = left;
        int j = right;
        int temp = s[left];
        while (i!=j){
            while (i<j&&s[j] >= temp) j--;
            while (i<j&&s[i] <= temp ) i++;
            if (i<j){
                int t = s[j];
                s[j] = s[i];
                s[i] = t;
            }
        }
        s[left] = s[i];
        s[i] = temp;
        System.out.println();
        quicksort(s,left,i-1);
        quicksort(s,i+1,right);
    }

改进后的快排

荷兰国旗问题

首先看一下经典的荷兰国旗问题。

现有红白蓝三个不同颜色的小球,乱序排列在一起,请重新排列这些小球,使得红白蓝三色的同颜色的球在一起。这个问题之所以叫荷兰国旗,是因为我们可以将红白蓝三色小球想象成条状物,有序排列后正好组成荷兰国旗。

将红白蓝三种颜色的球分别用0,1,2代替,我们就可以将这个问题视为一个数组排序问题。

解法一

遍历整个数组,记录下0,1,2的个数,再依次输出。

解法二

首先我们看另外一个题目

给定一个数组arr,和一个数num,请把小于num的数放在数组的 左边,等于num的数放在数组的中间,大于num的数放在数组的右边。

聪明的宝宝一定发现了,其实我们的荷兰国旗问题就是其中的Num=0的时候。那么,我们要怎么去做呢?

  1. 让cur指向数组的最左边,然后将less指向数组的最左边-1,more为最右边+1。(最左边-less的区域为小于区,more-最右边为大于区,所以一开始这两个区域都为0)
  2. 将cur和num进行比较,当大于num的时候就将more-1并与cur指向的数交换。小于num的时候就将less+1并与cur交换,交换后将cur+1。如果cur=num则直接Num++。
  3. 直到cur和more相遇则完成。假设图中的Num为3,执行情况将会如图所示。
    这里我们要注意的一个问题就是,当大于num的时候,我们的cur是不会+1的,因为此时我们无法确保交换过来的数是大于还是小于或者是等于Num,所以这个数还需要进行一次比较。但是如果与less+1的数交换,交换过来的数是之前比较过的,所以无需再比较,此时cur就需要+1。
    这里写图片描述
    Code:
public static int[] partition(int[] arr, int l, int r, int num) {
        int less = l - 1;
        int more = r + 1;
        while (l < more) {
            if (arr[l] < num) {
                swap(arr, ++less, l++);
            } else if (arr[l] > num) {
                swap(arr, --more, l);
            } else {
                l++;
            }
        }
        return new int[] { less + 1, more - 1 };
        //这里返回的是一个长度为2的数组,a[0]代表的是等于区域的第一个数,a[1]代表的是等于区域的最后一个数

改进快排

回顾一下普通快排,每一次它只解决了我们基准数一个数。假如我们用荷兰国旗问题来改进我们的过程,是不是就可以每一次解决多个相等的数呢?
Code:

    public static void quickSort(int [] a ){
        if (a==null||a.length < 2){
            return;
        }
        quickSort(a,0,a.length-1);
    }

    private static void quickSort(int[] a, int left, int right) {
        while(left<right){
            int[] p = partiction(a ,left,right);
            quickSort(a,left,p[0]-1);
            quickSort(a,p[1]+1,right);
        }
    }

    private static int[] partiction(int[] a, int left, int right) {
        //和最右边的数进行比较
        int less = left -1;
        int more = right;
        int cur = left;
        while(cur<more){
            if (a[cur]<a[right]){
                swap(a,++less,cur++);
            }else if (a[cur]>a[right]){
                swap(a,--more,cur);
            }else {
                cur++;
            }
        }
        swap(a,more,right);
        return new int[] {less+1 , more };
    }
    public static void swap(int[] arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }

随机快排

因为我们无法确保每一次划分的时候,正好划分在中间位置。所以我们采用随机快排,将数据状况变成一个概率问题。(通过长期期望证明复杂度为0(nlogn))

public static void quickSort(int[] arr, int l, int r) {
        if (l < r) {
            swap(arr, l + (int) (Math.random() * (r - l + 1)), r);//就是只要加这一行就好啦o(* ̄▽ ̄*)ブ
            int[] p = partition(arr, l, r);
            quickSort(arr, l, p[0] - 1);
            quickSort(arr, p[1] + 1, r);
        }
    }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值