【每日算法220522】分区快速排序的从0到1

今日题目

快速排序

通过选择数组的最右侧数作为分隔符,将数组分割成小于区域,等于区域,大于区域,周而复始,最终将数组排序。

今日心得

  • 数组相关的算法,一旦出现大量的systemcopy就说明不是最优解,没有充分利用数组空间。
  • 递归虽然理解很难,但是理解了解答就会很简单。只需要关注构建最小算法模型和边界条件。反而,使用非递归法的边界十分困难,非常容易出错。
  • 如果能画出纸上的过程,代码就实现了一半。否则,代码会卡在边界条件处理上,绕不出。

算法编码

package sort;

/**
 * @ClassName QuickSort
 * @Description 快速排序
 * <p>数组题一旦有太多copy就说明不是最优解,没有充分利用空间</p>
 * @Author kouryoushine
 * @Date 2022/5/22 10:20
 * @Version 1.0
 */
public class QuickSort {

    public static void main(String[] args) {
        int[] arr = {1, 3, 7, 5, 4, 3, 9, 8, 3, 7, 2, 3, 5, 7};
        quickSort(arr);
        for (int a = 0; a < arr.length; a++) {
            System.out.println(arr[a]);
        }
    }

    //用arr的最右数做区分,<=Rnum的放在左边,>Rnum的放在右边
    public static void splitByRnum(int[] arr) {
        if (arr == null || arr.length == 0) {
            return;
        }
        int N = arr.length;
        int lessArea = -1;
        int index = 0;
        ;
        int rNum = arr[N - 1];
        while (index < N) { //顺序遍历数组中每一个数
            if (arr[index] <= rNum) {  //当前数比最右数小,则交换位置。最小区域又阔,下标右移。
                swap(arr, lessArea + 1, index);
                lessArea++;
                index++;
            } else {  //当前数比最右大,则跳过,下标右移
                index++;
            }
        }

    }

    /**
     * 根据数组最右的值,将数据拆分成三个区域
     * 小区域:less=-1
     * 大区域:more=N-1
     * 等于区域: [less+1:more-1]
     * <p>
     * 实现逻辑:
     * index沿array遍历
     * 见代码注释
     *
     * @param arr
     */
    public static void splitNumByRnumIntoThreeAre(int arr[]) {
        int N = arr.length;
        int less = -1; //小区域有边界
        int more = N - 1; //大区域左边界
        int rNum = arr[N - 1];
        int index = 0; //下标
        while (index < more) {
            if (arr[index] < rNum) {
                swap(arr, less + 1, index);//小区域下一个数和当前值交换,下标和小区域右移
                index++;
                less++;
            } else if (arr[index] > rNum) { //大区域前一个值和当前值交换,大区域左移。index不变
                swap(arr, more - 1, index);
                more--;
                //index不变
            } else { //跳过
                index++;
            }

        }
        //index=more时
        swap(arr, index, N - 1);

    }

    /**
     * 分区快排,将上面能力进一步抽象为L...R范围内的排序,过程一样。
     *
     * @return ==区域的左右边界
     */

    public static int[] partiion(int[] arr, int L, int R) {
        int lessR = L - 1;
        int moreL = R;
        int rNum = arr[R];
        int index = L;
        while (index < moreL) {
            if (arr[index] < rNum) {
                swap(arr, lessR + 1, index);//小区域下一个数和当前值交换,下标和小区域右移
                index++;
                lessR++;
            } else if (arr[index] > rNum) { //大区域前一个值和当前值交换,大区域左移。index不变
                swap(arr, moreL - 1, index);
                moreL--;
                //index不变
            } else { //跳过
                index++;
            }
        }
        swap(arr, R, index);
        return new int[]{lessR + 1, moreL}; //moreL而不是moreL-1画出内存就知道了
    }

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


    }

    //递归函数
    public static void process(int[] arr, int L, int R) {
        if (L >= R) {
            return;
        }
        int[] equal = partiion(arr, L, R);//拆分成三个区域
        int L1 = L;
        int R1 = equal[0] - 1;
        int L2 = equal[1] + 1;
        int R2 = R;
        process(arr, L1, R1);
        process(arr, L2, R2);


    }


    public static void swap(int arr[], int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值