java.快速排序QuickSort

本文详细介绍了快速排序的三种实现方式:一路快速排序、二路快速排序和三路快速排序。每种方法的核心思想是通过一趟排序将数列划分为两部分,其中一部分记录的关键字均小于另一部分。一路快速排序简单直接,但处理大量重复元素效率较低;二路快排旨在优化处理相同元素的情况;三路快排则进一步将相等元素分开,提高效率。代码实现展示了每种排序的详细步骤和优化策略。
摘要由CSDN通过智能技术生成

记录一路快速排序、二路快速排序、三路快速排序的区别和改进

基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,比另一部分的关键字大,则可分别对这两部分记录继续进行排序,以达到整个序列有序。

一路快速排序步骤

1、从数列中挑出一个元素,设为V

2、重新排序数列,所有元素比V值小的摆放在V前面,所有元素比V值大的摆在V的后面(相同的数到右边),在这个分区退出之后,V就处于数列的中间位置。

3、递归把小于V的子数列和大于V的子数列排序。

缺点:是遇到大量相同元素会大大浪费时间复杂度,不符合期望

代码实现

public class QuickSort01 extends Sort{
    public QuickSort01(int[] arr) {
        super(arr);
    }
    @Override
    public void sort() {
        quickSort(0,arr.length - 1);
    }

    private void quickSort(int L, int R) {
        if (L >= R) {
            return;
        }
        //先对数组划分 并返回划分后的中点
        int p = partition(L ,R);
        quickSort(L, p - 1);//划分完的再排一遍
        quickSort(p + 1, R);
    }

    private int partition(int L, int R) {
        //优化一下 随机让后面的数字和第一个数字换一下
        //随机一个角标尽量避免极端情况
        //L = 5 R = 10   [0,5] + 5 = [5,10]
        swap(L, (int) (Math.random() * (R - L + 1) + L));
        int v = arr[L];//让首位在递归中继续当中值

        //arr[l+1 ~ j] < v < arr[j+1 ~ i)
        int j = L;
        for (int i = L + 1; i <= R; i++) {
            if (arr[i] < v) {
                swap(j + 1, i);
                j++;
            }
        }
        swap(L, j);//换位
        return j;
    }
}

二路快速排序

步骤

1、从数列中挑出一个元素,设为V

2、重新排序数列,左右两路各有一个游标,当左路游标i大于当前V,则由后遍历右路游标j,遇到比V小的就与当前左路游标i交换,这样反复直到两游标相遇。(代码操作中左i走到不小于V的停下,右j不大于V的停下,然后交换两个值再重复)

3、递归重复把小于V的子数列和大于V的子数列排序。

最终目的是将相等元素大致均分到两边,来减少后续递归的次数避免极端情况。

代码实现

//双路快速排序
public class QuickSort02 extends Sort {//实现抽象类
    public QuickSort02(int[] arr) {//引用父类构造副本
        super(arr);
    }

    @Override
    public void sort() {
        quickSort(0, arr.length - 1);
    }

    private void quickSort(int L, int R) {
        if (L >= R) {//判断
            return;
        }
        //对数组进行划分 并返回划分后的中点
        int p = partition(L, R);
        quickSort(L, p - 1);
        quickSort(p + 1, R);
    }

    private int partition(int L, int R) {
        //优化一下 随机让后面的数字和第一个数字换一下
        //尽量避免极端情况(升序情况)
        swap(L, (int) (Math.random() * (R - L + 1) + L));
        int v = arr[L];
        int i = L + 1;
        int j = R;
        while (true) {
            while (i <= R && arr[i] < v) {//判断i的角标不越界,走到一个不小于V的停
                i++;
            }
            while (j >= L + 1 && arr[j] > v) {//走到一个不大于V的停
                j--;
            }
            if (i > j) {//判断不越界
                break;
            }
            swap(i, j);
            i++;
            j--;
        }
        swap(L, j);//把V换到中间
        return j;
    }
}

三路快速排序

跟前两路的最大区别就是单独开辟一个中间区来存放相同的元素,再从两头遍历交换。

就像是对左边区与中间区做一路快排,将左边区合并中间区一起与右边区做二路快排。

代码如下

//三路快速排序
public class QuickSort03 extends Sort {
    public QuickSort03(int[] arr) {
        super(arr);
    }

    @Override
    public void sort() {
        quickSort(0, arr.length - 1);
    }

    private void quickSort(int L, int R) {
        if (L >= R) {
            return;
        }//随机一下元素
        swap(L, (int) (Math.random() * (R - L + 1) + L));
        int v = arr[L];
        int lt = L;
        int gt = R + 1;
        int i = L + 1;
        while (i < gt) {
            if (arr[i] < v) {//左边扩
                swap(i, lt + 1);
                lt++;
                i++;
            } else if (arr[i] > v) {//右边扩
                swap(i,gt - 1);
                gt--;
            } else {//中间区
                i++;
            }
        }
        //划分区
        swap(L,lt);
        quickSort(L,lt - 1);
        quickSort(gt, R);
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值