JAVA实现快速排序

声明

思路抄袭《啊哈,算法》,书写的更详细,值得一看

简易思路:

以一个数为标准,称为[基准数]
小于基准数的放左边
大于基准数的放右边
将其定为[移动规则]

移动之前
[3] 2 5 6 7 1 4

开始移动
[3] 2 5 6 7 [3] 4
以[3]为基准书,则经过第一次移动之后
1 2 [3] 6 7 5 4

第一次移动完成之后,再以基准数为边界
将其切割{1, 2} [3] {6, 7, 5, 4},
再分别对{1, 2}, {6, 7, 5, 4}进行相同规则的移动
递归行为

直到不可再切割,表示排序已完成。

具体实现

[3] 2 5 6 7 1 4
  1. 以[最左边]的数为基准[3]。
  2. 然后找两个侦察兵,从两端搜索。
    [3]. 一个从右往左搜找到小于基准数的,停在那里
  3. 一个从左往右搜找到大于基准数的,停在那里
    1. 没有相遇?两个交换位置
    2. 相遇?切割字符串
  4. 针对切割出来的两串数组,回到1

    实操

预备:
  #1表示侦察兵1号,任务是找到大于基准数的数字
  #2表示侦察兵2号,任务是找到小于基准数的数字

初始状态:
  (#1)[3] 2 5 6 7 1 (#2)4

开始行动
  (#1)[3] 2 5 6 7 1 (#2)4
  #2判断:4小于[3]吗?不小,继续

  (#1)[3] 2 5 6 7 (#2)1 4
  #2判断:1小于[3]吗?小,停,完成任务

  此时#1开始
  (#1)[3] 2 5 6 7 (#2)1 4
  #1判断:[3]大于[3]吗?不大,继续

  [3] (#1)2 5 6 7 (#2)1 4
  #1判断:2大于[3]吗?不大,继续

  [3] 2 (#1)5 6 7 (#2)1 4
  #1判断:5大于[3]吗?大,停,完成任务

  两个侦察兵都找到完成自己的任务了,交换数字(人质)。
  [3] 2 (#1)1 6 7 (#2)5 4

  继续查找
  [3] 2 (#1)1 6 (#2)7 5 4
  #2判断:7小于[3]吗?不小,继续

  [3] 2 (#1)1 (#2)6 7 5 4
  #2判断:6小于[3]吗?不小,继续

  [3] 2 (#1)(#2)1 6 7 5 4
  #2判断:判……不用判了,两个侦察兵都遇上了
  表示第一次移动结束,将相遇时的数与基准数交换
  这里是1和[3]交换

  1 2 (#1)(#2)[3] 6 7 5 4

  如此[3]就是边界,在[3]左边的小于[3],在[3]右边的大于[3]

  接着以[3]为边界切割数字
  {1, 2} 3 {6, 5, 7, 4}

  接着分别对{1, 2}{6, 5, 7, 4}进行同样的操作,可递归
  直到各个串被切割得只剩下一个数,此时排序已经结束

为什么选了最左边的数作为基准数,要右边优先开始搜索

假设我们以左端优先的

#1搜索,在5那里停住
  [3] 2 (#1)5 6 7 1 (#2)4
#2搜索,在1那里停住
  [3] 2 (#1)5 6 7 (#2)1 4
交换位置
  [3] 2 (#1)1 6 7 (#2)5 4
#1搜索,在6那里停住
  [3] 2 1 (#1)6 7 (#2)5 4
#2搜索,在1那里停住
  [3] 2 (#2)1 (#1)6 7 5 4

发现了吗?这两货明晃晃的放着敌方朝自己大本营去了,像瞎了一样没法发现他们相遇了。
无法判断相遇时没办法将基准数归位,更无法切割字符串,这序我不排了。

代码实现

public class QuickSqrt {

    static int[] nums = {3, 2, 5, 6, 7, 1, 4};

    public static void main(String[] args) {
        showArray();
        System.out.println("排序前:");
        quickSort(0, nums.length - 1);
        System.out.println("排序后:");
        showArray();
    }

    public static void quickSort(int startIndex, int endIndex) {
        if (startIndex > endIndex) {
            return;
        }
        //基准数
        int baseNum = nums[startIndex];
        //存储查找到的大于基准数的该数字在数组中的位置
        int leftIndex = startIndex;
        //存储查找到的小于基准数的该数字在数组中的位置
        int rightIndex = endIndex;

        while (leftIndex != rightIndex) {
            //查找小于基准数的数的位置
            while (nums[rightIndex] >= baseNum && rightIndex > leftIndex) {
                rightIndex--;
            }
            //查找小于基准数的数的位置
            while (nums[leftIndex] <= baseNum && leftIndex < rightIndex) {
                leftIndex++;
            }

            //如果没有相遇,表示可以交换,否则已经移动完毕
            if (leftIndex < rightIndex) {
                int tempNum = nums[leftIndex];
                nums[leftIndex] = nums[rightIndex];
                nums[rightIndex] = tempNum;
            }
        }

        //交换基准数与相遇位置的数
        nums[startIndex] = nums[leftIndex];
        nums[leftIndex] = baseNum;

        //以基准数为界,左右切割,再次排序
        quickSort(startIndex, leftIndex - 1);
        quickSort(leftIndex + 1, endIndex);
    }

    public static void showArray() {
        for (int i = 0; i < nums.length; i++) {
            System.out.print(nums[i]);
            if (i != nums.length - 1) {
                System.out.print(", ");
            }
        }
        System.out.println();
    }
}

结果

排序前:
3, 2, 5, 6, 7, 1, 4

排序后:
1, 2, 3, 4, 5, 6, 7

END

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值