算法与数据结构(6)—— 快速排序(随机化及优化)

前言:

快速排序和归并排序其实是差不多的,只不过就是归并不管数组内容是什么,直接一分为二,

而快排是选择一个元素,将其放在合适的位置,使左边的元素小于它,右边的大于它~这样逐渐递归~

它的核心就是Partition过程:

  • 通常使用数组的第一个元素来作为分界的标志点(基点),记为l(left)
  • 之后逐渐遍历右边所有未被访问元素
  • 在遍历的过程中逐渐整理让整个数组左部分小于 v 这个元素值,右部分大于 v。
  • 在此过程中,用j 来记录左右部分的分界点,当前访问的元素记为 i 。这样整个数组中 arr[l+1……j ] < v,arr[j+1……i-1] >v
  • 最后将l上的v和j交换,这样就切分成功了~

代码实现:

private static int partition(Comparable[] arr, int l, int r){

        Comparable v = arr[l];

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

    private static void sort(Comparable[] 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);
    }

    public static void sort(Comparable[] arr){

        int n = arr.length;
        sort(arr, 0, n-1);
    }

代码优化

(1) 优化一

还是递归到底的问题,高级的排序算法在底层时可以使用插入排序来优化快排,当元素较少时,可使用插入排序来提高性能~

(2) 优化二

提到过归并和快排都是分成两部分,归并是平分为二,整个层数就是logn层,每一层都是消耗O(n)时间

        但是快速划分的是选取的那个标志点、这样就会分成一大一小,假如选的最小或最大的那个点,那么情况更严重,即整个数组几乎有序~这样划分树的高度就是n, 每层消耗O(n),最终复杂度就是O(n^2)。

解决的办法就是:随机选取一个标记点~,但是这还是会出现最坏情况仍是O(n^2),只是说概率很低。

总结:

归并和快速尽管都是O(nlogn)级别的,但是快排是有常数级别的优势,即使已经对归并优化过了。

猜你喜欢

转载自blog.csdn.net/jae_wang/article/details/80555642