快速排序算法之java版(单路、双路、三路)

 快速排序算法的原理

快速排序算法是基于分治策略的另一个排序算法。其基本思想是,对于输入的子数组alp:r],按以下三个步骤进行排序。
①分解(Divide):以a[p]为基准元素将alp:r]划分成3段alp:q-1],a[q]和 a[q+1:r],使a[p:q-1]中任何一个元素小于等于a[q],而 a[q+1:r]中任何一个元素大于等于a[q]。下标q在划分过程中确定。
②递归求解(Conquer):通过递归调用快速排序算法,分别对ap:q-1]和 alq+1:r]进行排序。
合并(Merge):由于对'a[p:q-1]和 a[q+1:r]的排序是就地进行的,因此在 alp:q-1]和a[q+1:r]都已排好的序后,不需要执行任何计算,a[p:r]则已排好序。
基于这个思想,可实现快速排序算法如下:

private static <E extends Comparable<E>> void sort(E[] arr, int l, int r) {
        if (l >= r) {
            return;
        }
        int p = partition(arr, l, r); 
        sort(arr, l, p - 1);   // 对左半段排序
        sort(arr, p + 1, r);   // 对右半段排序
    }

        对含有n个元素的数组a[0:n-1]进行快速排序只要调用QuickSort(a,0,n-1)即可。

        上述算法中的函数Partition()以一个确定的基准元素a[p]对子数组 a[p:r]进行划分,它是快速排序算法的关键。

private static <E extends Comparable<E>> int partition(E[] arr, int l, int r) {

//        swap(arr,l,(l+r)/2);  将中间位置的元素和开始位置的元素做交换,作为基准

        // arr[l+1..j] < v; arr[j+1...i]>= v
        int j = l;
        for (int i = l + 1; i <= r; i++) {
            if (arr[i].compareTo(arr[l]) < 0) {
                j++;
                swap(arr, i, j);
            }
        }
        swap(arr, l, j);
        return j;

    }

交换的代码

 private static <E> void swap(E[] arr, int i, int j) {
        E t = arr[i];
        arr[i] = arr[j];
        arr[j] = t;
    }

上述为单路的快速排序,对于该快速排序,当数组中的元素本身已经有序的时,假设以第一个元素作为基准,一轮排序结束,待排序的元素只少了一个,如下所示:

此时时间复杂度为O(n^2)  递归深度为O(n)

容易看到,快速排序算法的性能取决于划分的对称性。通过修改函数Partition(),可以设计出采用随机选择策略的快速排序算法。在快速排序算法的每步中,当数组还没有被划分时,可以在a[p:sr]中随机选出一个元素作为划分基准,这样可以使划分基准的选择是随机的,从而可以期望划分是较对称的。随机化的划分算法可实现如下:

 只需要在partition函数里面,增加生成随机数的方法即可。

双路排序

之前说的快速排序算法是将>v和<v两个部分元素都放在索引值i所指向的位置的左边部分,而我们

的双路快速排序算法则不同,他使用两个索引值(i、j)用来遍历我们的序列,将<v的元素放在索

引i所指向位置的左边,而将>v的元素放在索引j所指向位置的右边,这也正是双路排序算法的

partition原理。



import java.util.Arrays;
import java.util.Random;


public class QuickSort {

    private static Random random;
    private QuickSort() {

    }

    
    public static <E extends Comparable<E>> void sort2ways(E[] arr) {
        random = new Random();
        sort2ways(arr, 0, arr.length - 1);
    }

    private static <E extends Comparable<E>> void sort2ways(E[] arr, int l, int r) {
        if (l >= r) {
            return;
        }
        int p = partition2(arr, l, r);
        sort2ways(arr, l, p - 1);
        sort2ways(arr, p + 1, r);
    }

    private static <E extends Comparable<E>> int partition2(E[] arr, int l, int r) {

        // 生成[l,r]之间的随机索引
        int p = l+random.nextInt(r-l+1);
        swap(arr,l,p);

        // arr[l+1...i-1]<= v;arr[j+1...r]>=v
        int i = l+1,j = r;
        while (true){

            while (i<=j && arr[i].compareTo(arr[l])<0)
                i++;
            while (j>=i && arr[j].compareTo(arr[l])>0)
                j--;

            if (i>=j)
                break;

            swap(arr,i,j);
            i++;
            j--;
        }
        swap(arr,l,j);
        return j;

    }


}

   三路排序

将整个数组按照划分值v,分成小于v的区域称为小于区,等于v的区域等于区和大于v的区域大于区三部分,在下一次的递归中就不必再处理等于v的等于区,因为等于区的元素已经到达了最终位置,对于存在大量等于v的数组三路快排大大提升了效率。

        

 /**
     * 三路快速排序
     * @param arr
     * @param <E>
     */
    public static <E extends Comparable<E>> void sort3ways(E[] arr) {
        Random rnd = new Random();
        sort3ways(arr, 0, arr.length - 1,rnd);
    }

    private static <E extends Comparable<E>> void sort3ways(E[] arr, int l, int r,Random rnd) {
        if (l >= r) {
            return;
        }
        // 生产 [l,r]直接的随机数
        int p = l + rnd.nextInt(r-l+1);
        swap(arr,p,l);

        // arr[l+1,lt]< v ,arr[lt+1,i-1] == v , arr[gt,r] >v
        int lt = l,i = l+1,gt = r+1;
        while (i<gt){
            if (arr[i].compareTo(arr[l])<0){
                lt++;
                swap(arr,i,lt);
                i++;
            }else if (arr[i].compareTo(arr[l])>0){
                gt--;
                swap(arr,i,gt);
            }else{ // arr[i]==arr[l]
                i++;
            }
        }

        swap(arr,l,lt);
        // arr[l,lt-1] < v ,arr[lt,gt-1] == v ,arr[gt,r]>v

        sort3ways(arr,l,lt-1,rnd);
        sort3ways(arr,gt,r,rnd);

    }

三路快速排序,对于数组中有大量重复的元素,更有优势。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值