算法回顾——快排

今天再复习一下快排:

当初看左神的算法课,受益匪浅。

他是先讲解了荷兰国旗问题,然后再引出的快排,如下:

荷兰国旗问题

给定一个数组arr,和一个数num,请把小于num的数放在数组的左边,等于num的数放在数组的中间,大于num的数放在数组的右边。

要求时间复杂度为O(N)、额外空间复杂度为O(1)。

分析:三个指针法:一个指向前头less,一个指向尾部more,一个是当前下标cur。当前下标由指向前面的指针推着前进。

public static int[] partition(int[] arr, int L, int R, int num) {
        int less = L-1;   //小于
        int more = R+1;   //大于【特别注意+1】
        int cur = L;      //等于
        while (cur<more) {
            if (arr[cur]<num) {
                swap(arr,++less,cur++);
            }else if (arr[cur]>num) {
                swap(arr,--more,cur);//【特别注意cur】
            }else {
                cur++;
            }
        }
        
        return arr;
    }
    
    private static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

快排

根据荷兰国旗问题,变形,让num=arr[arr.length-1],即是将比较的基准值变成数组arr的末尾值;

另外使得 R= arr.length-2; 将R变成数组 arr 中的倒数第二个值;

这样就形成了快排;

在这里,引入了一个“分治”的思想,以及求分治的边界点;

 

//根据荷兰国旗问题改进
public int[] quickSort3(int arr, int left, int right){
    if(left<right){
        int[] p = partition3(arr,left,right);//获得大小区间的临界
        quickQort3(arr,left,p[0]);//递归小区间
        quickQort3(arr,p[1],right);//递归大区间
        return arr;
    }
    
}
public int[] partition3(int[] arr, int L,int R){
    int left = L-1;
    int right = R;//这里和荷兰国旗不一样
    int cur = L;
    
    while(cur<right){
        if(arr[cur] < arr[R]){
            swap(arr,++left,cur++);
        }else if(arr[cur] > arr[R]){
            swap(arr,cur,--right);
        }else{
            cur++;
        }
    }
    swap(arr,R,right);//① :这里和荷兰国旗不一样:交换当前比对值到中间相等区;
    return new int[]{left+1,right};//②:这里和荷兰国旗不一样:返回小区间的右临界和大区间的左临界;
}

注:

在① 处:其实是把当前的比对基准值arr[R] 和大区间的左侧边界进行交换,这样 [L, left+1)就是小区间,(right,R]就是大区间【注意区间开闭,对应  步】

常学常乐

Over......

原文地址:https://www.cnblogs.com/gjmhome/p/14432646.html