八大基本排序---快速排序(经典快排、随机快排)(荷兰国旗问题)

引言:

clip_image002_thumb[1]

解答:

clip_image004_thumb[1]

需要准备3个下标

clip_image006_thumb[1]

如果当前数字=num,cur跳下一个

clip_image008_thumb[1]

如果数组中的当前数字<num,把这个数(3)和小于区域的下一个数(5)交换

clip_image010_thumb[1]

然后小于区域扩一下

clip_image012_thumb[1]

然后cur跳下一个位置

clip_image014_thumb[1]

数组中的当前数字<num,把这个数(2)和小于区域的下一个数(5)交换,

然后小于区域扩一下

然后cur跳下一个位置

clip_image016_thumb[1]

PS:

如果一上来遇到的就是cur<num

把这个数(3)和小于等于区域的下一个数(3)交换【自己和自己交换】

clip_image018_thumb[1]

数组中的当前数字>num,把这个数(7)和大于区域的前一个数(x)交换

然后大于区域向左扩一个位置,more移动一下

然后让cur停留在原地,继续考察换过来的x跟num的大小关系

clip_image020_thumb[1]

当cur == more的时候,整个过程停止

public class Code_08_NetherlandsFlag {

    public static int[] partition(int[] arr, int L, int R, int num) {
        int less = L - 1;
        int more = R + 1;
        while (L < more) {
            if (arr[L] < num) {
                swap(arr, ++less, L++);
            } else if (arr[L] > num) {
                swap(arr, --more, L);
            } else {
                L++;
            }
        }
        //less + 1:等于区域的第一个位置,more - 1:等于区域的最后 一个位置
        return new int[] { less + 1, more - 1 };
    }

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

传统快排:与荷兰国旗问题类似

image_thumb[1]

import java.util.Arrays;

//利用荷兰国旗问题进行快排
public class QuickSort {

    public static void main(String[] args) {
        int[] arr = {3,1,4,5,2,2,0,13};
        System.out.println(Arrays.toString(arr));
//        int[] res = new int[2];
//        res = partition(arr, 0, arr.length-1);
//        System.out.println(res[0]+" " +res[1]);
//        System.out.println(Arrays.toString(arr));
        quickSort(arr, 0, arr.length-1);
        System.out.println(Arrays.toString(arr));
        
    }
    
    public static void quickSort(int[] arr,int L,int R){
        if (L>=R) {
            return;
        }
        int[] p = partition(arr, L, R);
        quickSort(arr, L, p[0]-1);
        quickSort(arr, p[1]+1, R);
    }
    
    //以数组的最后一个数字arr[R]作为num
    //返回等于区域的下标
    public static int[] partition(int[] arr,int L ,int R){
        int less = L-1;
        int more = R+1;
        int num = arr[R];
        while (L < more) {
            if (arr[L]==num) {
                L++;
            }else if (arr[L]<num) {
                swap(arr,++less,L++);
            }else if (arr[L]>num) {
                swap(arr,L ,--more );
            }
        }
        int[] res = {less+1,more-1};
        return  res;
    }
    
    public static void swap(int[] arr, int i, int j ){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

 

经典快排存在的问题:

如果是一个有序的数组,算法的时间复杂度是O(N^2)

如果所选的num刚好把数组平分为左:<num;右>num,算法的时间复杂度是O(N*logN)

clip_image002[5]_thumb

一次只搞定了7这一个数字

下一次在<7的区间里,只搞定了6,划分为<6的区域和=6的区域

每一次都是一次O(N),所以总的是O(N^2)

或者

clip_image004[5]_thumb[3]

clip_image006[5]_thumb[1]

解决方法:随机快排

随机找到一个数,把这个数和最后一个数字交换,进行快排

clip_image008[5]_thumb[1]

clip_image010[5]_thumb[1]

这样最差情况就是在某个概率的情况下出现的,此时时间复杂度就是一个概率事件

此时时间复杂度的长期期望:O(N*logN)

快排的额外空间复杂度:O(logN)

空间用在记录划分点

clip_image012[5]_thumb[1]

clip_image014[5]_thumb[1]

猜你喜欢

转载自www.cnblogs.com/yuange678/p/10819720.html
今日推荐