快排,必拿下[java代码]

前导课

划分成<=P区和>P区

以最后一个元素作为划分值---假设为P,将整个数组划分成[ 小于等于P的区域 大于P的区域]

每个区域里无序

操作流程:

从左往右遍历,有两个分支逻辑

①若当前数<=P,则当前数和小于等于区的下一数交换,小于等于区右扩,指针移动到下一个位置(包括自己和自己交换)

②若当前数 > P,指针直接移动到下一个位置

指针来到终点位置时,停止循环

    //将arr分成 [<=p区  >p区]
    public static void splitNum1(int[] arr) {
        int lessEqualR = -1;//用此变量来表示<=p区域的右边界,区域扩到哪就写哪
        int index = 0;//遍历arr用
        int N = arr.length;
        while (index < N) {
            if (arr[index] <= arr[N - 1]) { //用数组中最后一个元素做划分值。即p
                //当前数<=p,则当前数和小于等于区的下一个位置做交换。交换完,index自增1.
                //由于lessEqualR也采用的自增,所以也早已经完成了右扩的任务
                //用lessEqualR的时候,是加1之后用1,用完后,还要加1更新,所以,直接写成++lessEqualR
                //用index的时候,是直接用,用完后要加1更新,所以,写成index++
                swap(arr, ++lessEqualR, index++);
                //这若写成lessEqualR++,则是错的。
            } else {
                index++;//直接跳下一个
            }
        }
    }
    public static void swap(int[] arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }

划分成<p区=p区>p区

将arr划分成[<p区 =p区 >p区]

操作流程:要用到两个区。还是拿最后一个数做划分值。还是从左向右遍历。

不同于上面,此流程中,刚开始的时候,小于区里没有一个数,但大于区里有最后一个数。

流程:

①若当前数<P,此数与小于区的下一个数交换,小于区右扩,index移到下一位

②若当前数 >P,,此数与大于区的前一个数交换,大于区左扩,index不动,因为此时index所指向的是刚从右边交换过来的数,还没看过,所以index停留在原地 ,从而看这个新数。

③若当前数=P,index直接移到下一位

当index与大于区的左边界撞上的时候,停止。然后单独让P与大于区的第一个数交换,至此,三个分区划分完毕

    //将[<p区  =p区   >p区]
    public static void splitNum2(int[] arr) {
        int N = arr.length;
        int lessR = -1;//小于区的右边界,一开始在-1.
        int moreL = N - 1;//大于区域的左边界,扩到哪就写到哪。一开始在N-1。即一开始大于区域就有一个数arr[N-1]
        int index = 0;//遍历arr
        // arr[N-1]的值做划分值
        while (index < moreL) {//index没撞上大于区的左边界时继续。撞上时,则结束循环
            //一共三个逻辑。很简单
            if (arr[index] < arr[N - 1]) {//当前数小于划分值,放小于区,小于区增长,index继续下一个位置
                swap(arr, ++lessR, index++);
            } else if (arr[index] > arr[N - 1]) {//当前数大于划分值,放大于区,大于区增长,index不动。停在原地看刚从右边换过来的数,因为此数
                //是刚换过来的,index这个指针还没看过他,所以,不动,留在原地看。
                //和大区域的前一个数交换。swap里传的是下标。
                swap(arr, --moreL, index);
            } else {
                index++;//上面都没中,说明当前数等于划分值,直接往下跳
            }
        }
        //单独让划分值与大于区的第一个值交换
        //划分值就是arr中的最后一个,也是大于区的最后一个,在上面的过程中,它一直未动,稳坐泰山。
        //大于区的第一个值就是左边界上的值
        swap(arr, moreL, N - 1);
    }

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

快排

递归下去,数组总有排好的时候。

在 前导课 里,将数组arr划分成3个区域的操作,称为 分区(动词),即partition。划分、分割、分区,怎么叫都行,你能理解它的神就ok了,名字只是形。

这是在抽象。大范围和小范围的操作是一样的。这就是递归。

public static int[] partition(int[] arr, int L, int R)
    返回的int[]是等于区域的左右边界,即等于区里的在左右边上的元素的下标。也就是说,
    把arr[L....R]划分成三部分后,我返回等于区域的左右边界
   ,为的是,告知上面,我这个等于区是有序的,左边和右边是无序的,左右需要排序,

详细注释版代码

    public static void swap(int[] arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
        //partition有分治、分割、分区的意思
    // arr[L...R]范围上,拿arr[R]做划分值,
    // L....R     < = >
    public static int[] partition(int[] arr, int L, int R) {
        //一定深刻记住,这是在[L...R]上操作
        //准备三个变量:
        int lessR = L - 1;//小于区的右边界
        int moreL = R;//大于区的左边界
        int index = L;//index从L遍历。
        while (index < moreL) {//写成 !=也可。index没撞上大于区的左边界时,继续
            if (arr[index] < arr[R]) {//arr[R]就是划分值
                swap(arr, ++lessR, index++);
            } else if (arr[index] > arr[R]) {
                //当前值大于划分值,则与大于区的前一个数交换,大于区左扩,idnex不动!!!
                swap(arr, --moreL, index);
            } else {
                index++;//当前值等于划分值,直接跳到下一个位置
            }
        }
        //最后,单独处理划分值(即最后一个数,也就是R所在的位置。在上述过程中它一直没动,稳坐泰山),让他与大于区的第一个数(即moreL所在位置)
        swap(arr, moreL, R);
        
        return new int[] { lessR + 1, moreL };//返回等于区域的左右两个边界。2 3 4 4 4 8 5 ,返回等于区的第一个4的下标和最后一个4的下标。
    //    用lessR和moreL来表示,就是lessR+1位置、moreL位置
    //这个边界是为了告知左侧和右侧是无序的,需要排序
    }

    //快排的主函数
    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) {
        //base case
        //L>R是无效范围,直接return,L=R时只有一个数,无需排,直接return,所以,可以整合写到一起
        /*
        if(L>R) return;
        if(L == R) return;*/
        if (L >= R) {
            return;
        }

        //上面不中。说明 L<R,不止一个数了。开始排

        //arr[L...R]上拿arr[R]做划分值进行划分,划分成3个区域,划分出的等于区的左右边界给给我(边界包括等于区的值).也就是说,等于区是从哪到哪,equalRange里存的就是这个。
        int[] equalRange = partition(arr, L, R);
        //equalRange[0] 是等于区的第一个值的下标
        //equalRange[1] 是等于区的最后一个值的下标
        process(arr, L, equalRange[0] - 1);//左边无序,排去吧
        process(arr, equalRange[1] + 1, R);//右边无序,排去吧
    }

无注释版+含对数器


/**
 * @author wbj
 * @create 2023-03-11 15:17
 */
public class QuickSortReview {
    public static void quickSort(int[] arr){
        if(arr == null || arr.length < 2){
            return;
        }
        process(arr,0,arr.length-1);//0到arr.length-1
    }
    //让arr[l...r]范围上有序
    public static void process(int[] arr,int l,int r){
        if(l >= r){
            return;
        }
        int[] equalRange = partition(arr, l, r);
        process(arr,l,equalRange[0]-1);
        process(arr,equalRange[1]+1,r);
    }
    //将arr[l...r]分成3个区域
    public static int[] partition(int[] arr,int l,int r){
        int lessR = l-1;
        int moreL = r;
        int index = l;
        while (index < moreL){
            if(arr[index] < arr[r]){
                swap(arr,++lessR,index++);
            } else if (arr[index] > arr[r]) {
                swap(arr,--moreL,index);
            }else{
                index++;
            }

        }
        swap(arr,r,moreL);
        return new int[]{lessR+1,moreL};
    }
    public static void swap(int[] arr,int i,int j){
        int t = arr[i];
        arr[i] = arr[j];
        arr[j] = t;
    }

    //test

    public static int[] getRandomArray(int size,int possible){
        int[] arr = new int[(int) (Math.random() * size) + 1];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = (int) (Math.random() * possible);
        }
        return arr;
    }
    public static int[] copyArray(int[] a){
        if(a == null || a.length == 0){
            return null;
        }
        int[] arr = new int[a.length];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = a[i];
        }
        return arr;

    }
    public static void main(String[] args) {
        int testTimes = 100;
        int size = 400;
        int possible = 1000000;
        System.out.println("测试开始");
        for (int i = 0; i < testTimes; i++) {
            int[] array = getRandomArray(size, possible);
            int[] copyArray = copyArray(array);
            quickSort(array);
            Arrays.sort(copyArray);

            for (int j = 0; j < array.length; j++) {
                if(array[j] != copyArray[j]){
                    System.out.println("error");
                }
            }

        }
        System.out.println("结束");
    }

}

复习

自己默写一遍。能写出来,说明你真正掌握了



/**
 * @author wbj
 * @create 2023-03-23 15:33
 */
public class QuickSort {
    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[] equalRange = partition(arr, l, r);
        process(arr,l,equalRange[0]-1);
        process(arr,equalRange[1]+1,r);

    }
    public static int[] partition(int[] arr,int l,int r){
        int lessR = l-1;
        int moreL = r;
        int index = l;
        while (index != moreL){
            if(arr[index] < arr[r]){
                swap(arr,++lessR,index++);
            } else if (arr[index] > arr[r]) {
                swap(arr,--moreL,index);
            }else{
                index++;
            }
        }
        swap(arr,moreL,r);
        return new int[]{lessR+1,moreL};
    }
    public static void swap(int[] arr,int i,int j){
        int a = arr[i];
        arr[i] = arr[j];
        arr[j] = a;
    }

    public static void main(String[] args) {

        int[] arr = {1,6,-2,-5,9,0,-88,77};
        quickSort(arr);
        for (int a : arr){
            System.out.print(a+" ");
        }
    }

}

感谢左神

猜你喜欢

转载自blog.csdn.net/weixin_60664694/article/details/129732445