排序高级算法(2)快速排序

快速排序

归并排序与快速排序都使用了「分治思想」

归并排序

拆分:不管数组的形态,总是将数组一分为二;
组合:合并两个有序的数组。

快速排序

拆分:根据某个元素 pivot,将数组整理成两个部分; 前半部分小于 pivot, 后半部分大于等于 pivot; 把 pivot 交换到前半部分的最后一个元素。
组合:什么都不用做。

快速排序的基本想法

快速排序每一次都排定一个元素(这个元素呆在了它最终应该呆的位置),然后递归地去排它左边的部分和右边的部分,依次进行下去,直到数组有序。

快速排序的算法思想

分而治之(分治思想),与「归并排序」不同,「快速排序」在「分」这件事情上不想「归并排序」无脑地一分为二,而是采用了 拆分 的方法,因此就没有「合」的过程。

演示代码:

import java.util.Arrays;

public class Quicksort {

  
    public static int[] sortArray(int[] nums) {
        int len = nums.length;
        quickSort(nums, 0, len - 1);
        return nums;
    }

    private static void quickSort(int[] nums, int left, int right) {
      
        if(left< right){
           int pIndex = partition(nums, left, right);
           quickSort(nums, left, pIndex - 1);
           quickSort(nums, pIndex + 1, right);}
    }

    private static int partition(int[] nums, int left, int right) {  
        // 基准值
        int pivot = nums[left];
        int lt = left;
        // 循环不变量:
        // all in [left + 1, lt] < pivot
        // all in [lt + 1, i) >= pivot
        for (int i = left + 1; i <= right; i++) {
            if (nums[i] < pivot) {
                lt++;
                swap(nums, i, lt);
            }
        }
        swap(nums, left, lt);
        return lt;
    }

    private static void swap(int[] nums, int index1, int index2) {
        int temp = nums[index1];
        nums[index1] = nums[index2];
        nums[index2] = temp;
    }


    public static void main(String[] args) {
        int[] a = {4, 54, -93, -34, 45, 68, 13, 45, 7, 33, -54};
        sortArray(a);
        System.out.println(Arrays.toString(a));
    }
}

快速排序优化

优化 1:

随机选择标定点元素,降低递归树结构不平衡的情况 由于快速排序在近乎有序的时候会非常差,此时递归树的深度会增加。此时快速排序的算法就退化为 O(N2);

解决办法:我们在每一次迭代开始之前,随机选取一个元素作为基准元素与第 1 个元素交换即可。

优化 2:

小区间使用插入排序

优化代码:

import java.util.Arrays;
import java.util.Random;

public class Quicksort {

    private static final Random RANDOM = new Random();

    private static final int INSERTION_SORT_THRESHOLD = 7;


    public static int[] sortArray(int[] nums) {
        int len = nums.length;
        quickSort(nums, 0, len - 1);
        return nums;
    }

    private static void quickSort(int[] nums, int left, int right) {
        //优化一:小区间使用插入排序
        if (right - left <= INSERTION_SORT_THRESHOLD) {
            insertionSort(nums, left, right);
            return;
        }

        int pIndex = partition(nums, left, right);
        quickSort(nums, left, pIndex - 1);
        quickSort(nums, pIndex + 1, right);
    }

    private static int partition(int[] nums, int left, int right) {
        //优化二:随机选取一个元素作为基准元素与第 1 个元素交换
        int randomIndex = RANDOM.nextInt(right - left + 1) + left;
        swap(nums, left, randomIndex);

      
        int pivot = nums[left];
        int lt = left;
  
        for (int i = left + 1; i <= right; i++) {
            if (nums[i] < pivot) {
                lt++;
                swap(nums, i, lt);
            }
        }
        swap(nums, left, lt);
        return lt;
    }

    private static void swap(int[] nums, int index1, int index2) {
        int temp = nums[index1];
        nums[index1] = nums[index2];
        nums[index2] = temp;
    }

    private static void insertionSort(int[] nums, int left, int right) {
        for (int i = left + 1; i <= right; i++) {
            int temp = nums[i];
            int j = i;
            while (j > left && nums[j - 1] > temp) {
                nums[j] = nums[j - 1];
                j--;
            }
            nums[j] = temp;
        }
    }

    public static void main(String[] args) {
        int[] a = {4, 54, -93, -34, 45, 68, 13, 45, 7, 33, -54};
        sortArray(a);
        System.out.println(Arrays.toString(a));
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值