优化快速排序(荷兰国旗问题)JAVA

荷兰国旗问题:

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

思路:
先定义一个left指针,比原数组arr左边界小1。然后再定义一个right指针,比原数组右边界大1。然后还有一个遍历数组的指针index。
然后依次遍历arr[index],如果小于num,则将left加1,然后把left位置的数和index位置交换。这一步是什么意思呢?left的含义就是保存比num小的数的边界,如果index遍历到一个比num小的数时,此时把left下一位的数和index位置交换,然后left右移一位吗,index加1。这也是为什么初始设定left比原数组arr左边界小1,right比原数组右边界大1,因为初始边界内应该不包含任何数。 同理,如果arr[index]比num大,则right下一位和index交换,然后right左移一位。但是,此时index不加1,这点是left和right移动时的区别。因为此时right换到index位置的数还没进行过和num对比,从前面换过来的数是已经比较过的,应该==num,而后面数还没遍历到 当arr[index]等于num,则只有index++。

public static int[] DutchFlag(int[] arr,int num,int l,int r){
        int left=l-1;
        int right=r+1;
        int index=l;
        while(index<right){
            if(arr[index]<num){
                swap(arr,++left,index);
                index++;
            }else if(arr[index]>num){
                swap(arr,index,--right);
            }else {
                index++;
            }
        }
        return new int[]{left+1,index-1};
    }

    private static void swap(int[] arr,int l1,int l2) {
        int temp=arr[l1];
        arr[l1]=arr[l2];
        arr[l2]=temp;
    }

用荷兰国旗问题优化快速排序问题:

经典快速排序问题,是每次选取第一个或者最后一位,然后递归实现。这里讲荷兰国旗问题,就是为了优化经典快速排序问题。
优化一:
可以看到,经典快速排序,每次只有一个元素到达最终位置,而荷兰国旗问题,可以看到,最终返回的是中间等于某个数的一个区间,相当于,荷兰国旗问题,每次可以将一组相同的数放到最终位置上,而不是经典快排的一个数。
优化二:
第二点优化其实就和荷兰国旗问题没什么关系了。经典快排,要么每次从第一个位置选择元素,要么从最后一个位置选择元素,如果原数组有序,那么时间复杂度就是n²。如果改为随机数组中任意一个数的话,(int)Math.random()*(right-left+1),那么就变成一个概率问题,有人经过严格数学推导,随机的话,时间复杂度就是nlogn,能有效避免n²:
代码:

public static void quickSort(int[] arr,int left,int right){
        if(left>=right){
            return;
        }
        //(int)Math.random()*(right-left+1)随机选取数组中一个数
        int[] ar = DutchFlag(arr, arr[left+(int)Math.random()*(right-left+1)], left, right);
        quickSort(arr,left,ar[0]-1);
        quickSort(arr,ar[1]+1,right);
    }

    public static int[] DutchFlag(int[] arr,int num,int l,int r){
        int left=l-1;
        int right=r+1;
        int index=l;
        while(index<right){
            if(arr[index]<num){
                swap(arr,++left,index);
                index++;
            }else if(arr[index]>num){
                swap(arr,index,--right);
            }else {
                index++;
            }
        }
        return new int[]{left+1,index-1};
    }

    private static void swap(int[] arr,int l1,int l2) {
        int temp=arr[l1];
        arr[l1]=arr[l2];
        arr[l2]=temp;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值