首页 > 其他分享 >快排

快排

时间:2022-08-18 22:59:09浏览次数:51  
标签:小于 arr int 快排 num 数组 等于

快排

例1

给定一个数组arr,和一个数num,请把小于等于num的数放在数组的左边,大于num的数放在数组右边,要求额外空间复杂度O(1),时间复杂度O(N)

解法:

0、我们指定一块区域,称之为小于等于区,在这个区域里面,存储着小于num的数

1、遍历arr数组,如果arr[i]<=num,arr[i]和 在小于等于区的下一个数交换,然后小于等于区右扩,i++

2、遍历数组arr,如果arr[i] > num,i++,跳过

3、越界了停

例2:例1的派生 荷兰国旗问题

给定一个数组arr和一个数num,请把小于num的数放在数组的左边,等于num的数放在数组的中间,大于num的数放在数组的右边,要求额外空间复杂度O(1),时间复杂度O(N)

解法:

0、指定2块区域,一个是小于区,另一个是大于区

1、遍历arr数组,如果arr[i] < num,arr[i]和 在小于区的下一个数交换,然后小于区右扩i++

2、遍历数组arr,如果arr[i] = num,i++,跳过

3、遍历数组arr,如果arr[i] > num,arr[i]和大于区的前一个交换,然后大于区右扩,i不变

4、当i和大于区的边界相重合的时候,遍历停止

//在arr[L...R]上进行荷兰国旗问题,以arr[R]作为指定的num划分值
//小于arr[R]放在左边,等于arr[R]的放在中间,大于arr[R]放在右边
//返回等于区域的左右 边界
public static int[] netherlandFlag(int[] arr, int L, int R){
    //如果左边比右边还大直接错误了,返回-1
    if(L > R){
        return new int[]{-1, -1};
    }
    //如果左右边界相等,直接返回左右边界
    if(L == R){
        return new int[]{L, R};
    }
    //小于区右边界
    int less = L -1;
    //大于区左边界,这里先把arr[R]算作已经进入右边界,先不考虑它移动,因为他是划分值
    int more = R;
    //让当前循环的数字下标从最左端进入
    int index = L;
    //当前循环的数字下标不能超过最右端的
    while(index<more){
        //假如当前的数字等于制定的数字
        if(arr[index] == arr[R]){
            //直接跳过这个数字,它的位置不需要动
            index++;
        }else if(arr[index < arr[R]){
            //假如当前的数字小于指定的数字,那么他要和小于区的下一个进行互换,并且小于等于区向后移动一个,最后进入下一个数字进行判断
            swap(arr,index++,++less);
        }else{
            //假如当前的数字大于指定的数字,他和大于区的前一个进行交换,并且大于区向前移动一位,但是当前的数字不能在往前移动,因为当前index所在的数字是从原大于区调换过来的,还没有进行判断
            swap(arr,index,--more);
        }
     }
     //把所有的都判断完后,让最后这个指定数字,和大于区的第一位进行互换,就得到了荷兰国旗算法以后的数字
     swap(arr ,more, R);
     //返回等于区域的边界
     //【左(小于区的下一个less+1)右(原本应该是大于区的前一个,但是大于区的第一个跟指定的数交换了,所以就是大于区的死第一个more)】
     //[小于区(L...less),等于区(less+1,more),大于区(more+1...R)]
     return new int[] {less + 1, more};
}
public static void swap(int[] arr, int i, int j){
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}

快排1.0版本 O(N^2)

假设有一个数组,这个数组的最后一位是X

(1)整体进行进行partition

假如小于等于X的,我们把它放在数列的左端小于等于区比X大的放在右边大于区,最后把X和大于区的第一个互换(也就是小于等于区的最后后一个数),这样我们就把X排好了,但左侧小于等于区里,很有可能还有X,我们下一步继续partition左侧的小于等于区

 

(2)继续对部分进行partition

左边小于等于区继续进行partition,设这个区域的最后一个数是X',和第一步一样搞定X'在中间

右边大于等于区继续进行partition,设这个区域的最后一个数是X‘’,和第一步一样搞定X'‘在中间

........周而复始得到最后的结果

 

public static void quickSort1(int[] arr){
    if(arr == null || arr.length < 2)
        return;
    process1(arr, 0, arr.length-1);
}
//递归的快排
public static void process1(int[] arr, int L, int R){
    if(L >= R)
        return;
    //在arr[L..R]上 进行partition方法 arr[R]=X 将arr变成:[ <=X, X, >X]
    //返回值M表示X最后落在哪里了
    int M = partition(arr, L, R);
    process1(arr, L, M-1);
    process1(arr, M+1, R);
}

 

快排2.0版本 O(N^2)

直接利用荷兰国旗算法,直接将等于X的全部固定在数组中间,剩下继续利用递归,把左右两块区域的X' X''固定住

 

public static void quickSort2(int[] arr){
    if(arr == null && arr.length == 0)
        return;
    process2(arr, 0, arr.length - 1);
}
public static void process2(int[] arr, int L, int R){
    if(L>R)
        return;
    //得到是中间等于区域的左右边界下标
    int[] equalArea = netherlandFlag(arr, L, R);
    //继续从最左边L,到小于区域的最右边,中间等于区域的左边前一位(equalArea[0])下标-1递归
    process2(arr, L, equalArea[0] - 1);
    //继续从中间等于区域的右边的下一位(equalArea[1])下标+1,到最右大于区域边R递归
    process2(arr, equalArea[1] + 1, R)
}

快排3.0版本 O(N*logN)

我们在数组中随机选一个数作为X,并且把它放到数组的最后一个上,然后和快排2.0执行一样的操作

public static void quickSort3(int[] arr){
    if(arr == null && arr.length == 0)
        return;
    process3(arr, 0, arr.length - 1);
}
public static void process3(int[] arr, int L, int R){
    if(L > R)
        return;
    //在数组中,L-R的范围上随机选一个数字,作为X
    int X = (int) (Math.random() * (R - L + 1)); 
    //并且把这个X放在
    swap(arr, X, R);
    int[] equalArea = netherLandFlag(arr, L, R);
    process3(arr, 0, equalArea[0] - 1);
    process3(arr, equalArea[1] + 1, R);
}

标签:小于,arr,int,快排,num,数组,等于
From: https://www.cnblogs.com/phonk/p/16600403.html

相关文章

  • 经典算法之快排
    快排的复杂度快排逻辑快速排序算法通过多次比较和交换来实现排序,其排序流程如下:首先设定一个分界值(基准值),通过该分界值将数组分成左右两部分。将大于或等于分界值......
  • LeetCode912 排序数组(手撕快排)
    LeetCode912排序数组classSolution:defsortArray(self,nums:List[int])->List[int]:importrandomdefpartition(l:int,r:int......