快速排序的三种实现方法

快速排序:

        快速排序是一种分而治之的思想,把需要排序的序列划分成小的序列,再层层划分直至每个序列只有一个数字为止,而在每次划分中至少能确定一个数字,即基准数的位置,最终完成排序,以下排序均是从小到大进行排序。

一、挖坑法

        把左指针所指向的数视为基准数(坑),left为左指针,righ为右指针,左边的数字都比基准数(坑)小;右边的数字都比基准数(坑)大。

每次比较如果右指针满足条件则左移,即 if(nums[right] > temp) right-- ;当不满足条件时,把右指针所指的值赋值给左指针,同时从左指针开始比较,如果满足左指针所在的数据小于基准数if(nums[right] > temp) left++ ,直到left == right结束,而此时left的位置即为基准数的位置,把基准数防至left的位置即可。

第一次交换:考虑到要把基准数作为交换数去比较,如果选择的基准数在左边,则从右边开始比较,如果选择的基准数在右边,从左边开始比较,这样可以保证开始被替换的数字永远是基准数。

左指针不满足条件,将左指针指代的数赋值给右指针指代的数。

同理,右指针进行比较

此时 left = right,而left的位置即为基准数的位置,把left所在的值替换为基准数,完成第一次排序。

......

依次下来,把基准数左边的和右边的作为新排序对象再次进行排序,最终所有的数字都是有序的。

代码示例:

public class QuickSort02 {
    public static void qSort(int[] nums) {
        qulifier(nums, 0, nums.length - 1);
    }

    public static void qulifier(int[] nums, int left, int right) {
        if (left < right) {
            int db = updateAndSwap(nums, left, right);
            qulifier(nums, left, db - 1);
            qulifier(nums, db + 1, right);
        }
    }

    public static int updateAndSwap(int[] nums, int left, int right) {
    int tmp = nums[left];
    //当左指针 < 右指针执行
    while (left < right) {
        //当左指针 < 右指针 且右指针所指的数大于基准数
        while (left < right && nums[right] <= tmp){
            right--;
        }
        //右指针指向的数小于基准数 则把左指针所在的数替换为右指针 即提出基准值
        if(left < right){
            nums[left] = nums[right];
        }
        //当左指针 < 右指针 且左指针所指的数小于基准数
        while (left < right && nums[left] >= tmp){
            left++;
        }
        //当左指针指向的数大于基准数 则把右指针所在的数替换为左指针
        if(left < right){
            nums[right] = nums[left];
        }
        
        //当左指针与右指针重合 即把基准值放置到目标数组正确位置
        if(left == right){
            nums[left] = tmp;
        }
    }
    return left;
}

    public static void show(int[] nums) {
        Arrays.stream(nums).forEach(System.out::print);
    }

    public static void main(String[] args) {
        int[] nums = {0,2,3,1,9,8,7,4,6,5};
        qSort(nums);
        show(nums);
    }
}

二、左右指针法

        左右指针法思想同挖坑交换法类似,不同的是左右指针法是以交换的方式,而挖坑法是以取代的方式。左指针负责寻找比基准数小的数,如果找到比基准数大的,右指针开始寻找比基准数的,如果找到比基准数小的,把左指针与右指针所指向的数交换。当左指针等于右指针时,左指针的值与基准值交换,完成一次排序,依次类推分为左右两组进行,最终完成排序。

左右指针第一次找到位置并交换:

交换后:

第二次找到位置并交换:

第三次找到位置:当left = right时,确定基准值的位置,把left与right所指向的数与基准值进行交换,完成第一次排序。

代码示例:

public class QuickSort03 {
    public static void qSort(int[] nums){
        pointSwap(nums,0,nums.length - 1);
    }

    public static void pointSwap(int[] nums,int left,int right){
        if(left < right){
            int index = partSwap(nums,left,right);
            pointSwap(nums,left,index - 1);
            pointSwap(nums,index+1,right);
        }
    }

    public static int partSwap(int[] nums,int left,int right){
        int begain = left;
        int end = right;
        int key = right;
        while(begain < end){
            while (begain < end && nums[begain] <= nums[key]){
                begain++;
            }
            while (begain < end && nums[end] >= nums[key]){
                end--;
            }
            swap(nums,begain,end);
        }
        swap(nums,begain,right);
        show(nums);
        return begain;
    }

    public static void swap(int[] nums,int leftIndex,int rightIndex){
        int temp;
        temp = nums[leftIndex];
        nums[leftIndex] = nums[rightIndex];
        nums[rightIndex] = temp;
    }

    public static void show(int[] nums){
        Arrays.stream(nums).forEach(System.out::print);
        System.out.println();
    }

    public static void main(String[] args) {
        int[] nums = {1,3,2,9,6,4,7,8,5,0};
        qSort(nums);
        show(nums);
    }
}

三、前后指针法

        前后指针法也是在保证两组数据,一组大于基准数,一组小于基准数,使用两个相邻的指针从左往右开始筛选数据较基准数 key 的比较,其思想是设置一个 now指针,即寻找指针,now指针的作用是寻找比基准数小的数据,prev指针的作用是标记比基准数大的数字。当now指针查找的数据均大于key的值时,now指针前移,即now++,直到now指针所指向的数小于 key 基准数。当now指针查找的数据满足条件,且prev指针与now指针不相邻时,进行交换,即(nums[now] < key )&& ++prev != now时进行交换。

        初始位置,now指针从起始位置开始,prev指针在now指针之前,即prev = --now,本次排序从小到大排序。now指针寻找的数为比基准数小的数字,在now指针找到之前,prev指针将保持不动。找到比基准数小的数且now指针与Prev指针不指向同一个数(交换没有意义),则交换now指针与prev指针指向的数。

第一次位移,因为prev == now 不进行交换

第二次位移:prev < now 交换

依次往下交换:

最后当Now指针与key所在的位置相等时,把prev指针前移一位,与key所指向的数交换,最后返回prev的值,即为确定了当前基准数的位置,并开始其他基准数的排序。

代码示例:

public class QuickSort04 {
    public static void qSort(int[] nums){
        partSort(nums,0,nums.length - 1);
    }

    private static void partSort(int[] nums, int left, int right) {
        if(left < right){
            int index = updateAndSwap(nums,left,right);
            partSort(nums,left,index - 1);
            partSort(nums,index+1,right);
        }
    }

    public static void swap(int[] nums,int index1,int index2){
        int tmp;
        tmp = nums[index1];
        nums[index1] = nums[index2];
        nums[index2] = tmp;
    }

    private static int updateAndSwap(int[] nums, int left, int right) {
        int cur = left;
        int prev = left - 1;
        int key = nums[right];
        while (cur < right){
            // &&符号当左边检测为假时  不执行右边判断条件
            if(nums[cur] < key && ++prev != cur){
                swap(nums,cur,prev);
            }
            cur++;
        }
        swap(nums,++prev,right);
        show(nums);
        return prev;
    }

    public static void show(int[] nums){
        Arrays.stream(nums).forEach(System.out::print);
        System.out.println();
    }

    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        int[] nums = {1,5,6,7,0,3,2,9,8,4};
        qSort(nums);
        show(nums);
        System.out.println(System.currentTimeMillis() - start);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值