3.4 快速排序算法的java实现

快速排序

1.理论基础

1.1 什么是快速排序

快速排序简称快排,它是在实践中最快的已知排序算法,根据相关测试,其平均运行时间为O(N logN)

它的基本思想是:
如果我们需要对数组S进行排序

  • 如果S中的元素个数为0或1,直接返回
  • 取S中任意一个元素v,并称其为key
  • 以v大小为界限将S-v部分分为S1(小于v的集合),S2(大于v的集合)
  • 递归的对S1,S2做上面同样的快排操作,最终得到一个有序的数组

如下图所示:

其中关键的一部就是:

如何通过key对集合S进行划分,划分的过程就是快排的关键。
并且如何取得这个key也是算法的关键

1.2 如何得到key

虽然从算法上看,无论选择那个元素作为key,最后快速排序都能正确的完成工作,但是有些选择明显能让快速排序更快的完成工作。

(一般没有经过考虑的做法是将第一个元素作为key,如果排序的数组是随机的,这个做法是可以接受的,但是,

如果数组是预排序或反序的,这样的做法绝对是很糟糕的,还有的做法是选择前两个互异元素的大者,当然这样也是不好的)

目前已知的较好的做法是: 三数中值法

选择数组左端,右端,中心位置的三个元素中的中值作为key,这种取值的做法能在一定程度上消除数组特性带来的坏影响。

1.3 快速排序是如何通过key进行划分的

我们先看一个数组 , array = {8,4,3,9,0,1},以这个数组为例
做法如下:

  • 首先使用三数中值法得到array的key = 3
  • 然后将key元素和最后一个位置的元素交换得到array = {8,4,1,9,0,3}
  • 定义i=0,j = array.length-2
  • 使用如何规则对array进行处理:
    1. 判断array[i]是否大于key,如果大于则i的值不变,否则i自增向后移动直到array[i]大于key
    2. 判断array[j]是否小于key,如果小于则j的值不变,否则j自减向前移动直到array[j]小于key
    3. 交换i,j位置上的值,并保持i,j不变
    4. 重复前面三步的操作直到i>=j
    5. 将i位置上的元素和key进行交换,划分完毕

具体图示如下:

2.java完整代码实现

public class intQuickSort {

  public static void main(String[] args) {
    int[] numbs = {5,1,1,2,0,0};
    quickSort(numbs);
    System.out.println(Arrays.toString(numbs));
  }


  /**
   * 三数中值找到key并和right位置交换
   * @param a 目标数组
   * @param left 左位置
   * @param right 右位置
   * @return
   */
  public static int median3(int[] a, int left,int right) {
    int center = (left+right)/2;
    // left为中值
    if(a[left]>=a[center]&&a[left]<=a[right]||a[left]>=a[right]&&a[left]<=a[center]){
      swap(a,left,right);
    }
    // center为中值
    else if(a[center]>=a[left]&&a[center]<=a[right]||a[center]>=a[right]&&a[center]<=a[left]) {
      swap(a,center,right);
    }
    return a[right];
  }

  /**
   * 随机选取key
   * @param a
   * @param left
   * @param right
   * @return
   */
  public static int randomKey(int[] a,int left,int right) {
    Random random = new Random();
    int index = random.nextInt(right-left+1)+left;
    swap(a,index,right);
    return a[right];
  }

  /**
   * 交换left和right位置的元素
   * @param a
   * @param left
   * @param right
   */
  public static void swap(int[]a ,int left,int right) {
    if(left<0||right<0||left>=a.length||right>=a.length){
      System.out.println("left或right位置错误!!");
    }
    int tem = a[left];
    a[left] = a[right];
    a[right] = tem;
  }

  /**
   * 2个或三个的元素就不用执行主流程了,直接进行普通的排序
   * @param a
   * @param left
   * @param right
   */
  public static void easySort(int[] a, int left, int right) {
    int center = left+1;

    if(a[left]>a[center]){
      swap(a,left,center);
    }

    if(a[left]>a[right]){
      swap(a,left,right);
    }

    if(a[center]>a[right]){
      swap(a,center,right);
    }

  }

  public static void quickSort(int[] a){
    quickMain(a,0,a.length-1);
  }

  public static void quickMain(int[] a, int left, int right) {
    if(left>=right||right<0||left>=a.length||left<0||right>=a.length) {
      return;
    }
    //如果元素超过3个,执行快排流程
    if(left+3 <= right) {
      int i ,j = right-1 ,key;
      //key = median3(a,left,right);
      key = randomKey(a,left,right);
      for(i = left;i <= j;) {
        if(a[i] <= key) {
          i++;
        }
        if(a[j] >= key){
          j--;
        }
        if(i<j&&a[i]>key&&a[j]<key){
          swap(a,i,j);
        }
      }
      swap(a,i,right);
      // 此时i位置就是中间位置
      // 需要对剩下的元素进行快排操作
      quickMain(a,left,i-1);
      quickMain(a,i+1,right);
    }
    // 简单排序
    else{
      easySort(a,left,right);
    }
  }
}

时间复杂度最坏为:O(n^2) 最好为O(nlogn) 平均为:O(n log(n))

空间复杂度:O(1)

相比于前者,快速排序又优秀了许多!! 快速排序是必须要掌握的一种排序方法。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员小牧之

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值