zoukankan      html  css  js  c++  java
  • 快速排序

    快速排序比一般的排序算法都要快,它是原地排序(只需要一个很小的辅助数组),且将长度为N的数组排序所需的时间与NlgN成正比.

    基本算法

    快速排序也是一种分治算法,它将一个数组分成两部分分别排序,它和归并排序是互补的.

    归并排序是将一个数组分成两个子数组分别排序,并将有序子数组归并以将整个数组排序;而快速排序将数组排序的方式是子数组有序时整个数组也是有序的.

    在快速排序中,切分的位置取决于数组的内容.

    代码实现

        public static void sort(Comparable[] a){
            sort(a,0,a.length-1);
        }
        
        public static void sort(Comparable[] a, int lo, int hi){
            if(lo>=hi) return ;//递归出口
            int j = partition(a,lo,hi);    //切分元素
            sort(a,lo,j-1);    //左半部分排序
            sort(a,j+1,hi);    //右半部分排序
        }

    快速排序递归地将子数组a[lo..hi]排序,先用partition()方法将a[j]放到一个合适的位置,然后再递归将其他元素排序.

    关键在于切分,这个过程使数组满足三个条件:

    对于某个j,a[j]已经排定.

    a[lo]到a[j-1]中所有元素都不大于a[j].

    a[j+1]到a[hi]中所有元素都不小于a[j].

    切分方法的实现

    先随意取a[lo]作为切分元素,即那个会被排定的元素.

    然后从数组的左端扫描直到找到一个大于等于它的元素,再从数组的右边扫描直到找到一个小于等于它的元素. 这两个元素显然没有排定,所以我们交换他们的位置

    如此继续,我们可以保证左指针i的左侧元素都不大于切分元素,右指针j的右侧元素都不小于切分元素. 当两个指针相遇时,我们只要把切分元素a[lo]和左子数组最右边元素a[j]进行交换即可,这时切分元素就留在了a[j]中了.

     

    轨迹图

    算法实现

        public static int partition(Comparable[] a, int lo, int hi){
            int i = lo, j = hi + 1;    //左右扫描指针
            Comparable v = a[lo];    //切分元素
            while(true){
                //扫描到左半部分大于v的元素停止
                while(less(a[++i], v)) if(i==hi) break;
                //扫描到右半部分小于v的元素停止
                while(less(v,a[--j])) if(j==lo) break;
                if(i>=j)
                    break;
                //交换元素
                exch(a,i,j);
            }
            //交换切分元素a[lo]和左半部分最右边的元素a[i].因为a[lo]到a[j-1]中的所有元素都不大于a[j]
            exch(a,i,lo);
            return j;
        }

    优化

    1.在排序小数组时切换到插入排序

    2.三取样切分(取样大小为3设中间的元素为切分元素),代价是需要计算中位数.

    3.熵最优排序

     三向切分的快速排序

    快速排序的一种改进,使快排在有大量重复元素的数据,同样能保持高效。

    我们从左到右遍历数组,维护一个指针lt使得a[lo..lt-1]中的元素全部小于v,一个指针gt使得a[gt+1..hi]中的元素全部大于v,一个指针i使得a[lt,i-1]中的元素都等于v,a[i,gt]中的元素都还未确定.

     

    一开始令i和lo相等,遍历过程中有3种情况

    a[i] < v, 将a[i]和a[lt]交换,将lt和i都加一.

    a[i] > v, 将a[i]和a[gt]交换,将gt减一.

    a[i] == v ,将i加一.

    这些操作保证数组元素不变且缩小gt-i的值(这样循环才能终止)

        public static void sort(Comparable[] a, int lo, int hi){
            if(hi <= lo) return ;
            int lt = lo, gt = hi,i = lo + 1;
            Comparator v = a[lo];
            while(i<=gt){
                int cmp = a[i].compareTo(v);
                if(cmp>0) exch(a,i,gt--);
                else if(cmp<0) exch(a,i++,lt++);
                else    i++;
            }
            //现在 a[lo..lt-1] < v = a[lt..gt] < a[gt+1..hi]成立
            sort(a,lo,lt-1);
            sort(a,gt+1,hi);
        }

     算法轨迹

  • 相关阅读:
    PAT (Advanced Level) 1086. Tree Traversals Again (25)
    PAT (Advanced Level) 1085. Perfect Sequence (25)
    PAT (Advanced Level) 1084. Broken Keyboard (20)
    PAT (Advanced Level) 1083. List Grades (25)
    PAT (Advanced Level) 1082. Read Number in Chinese (25)
    HDU 4513 吉哥系列故事――完美队形II
    POJ Oulipo KMP 模板题
    POJ 3376 Finding Palindromes
    扩展KMP
    HDU 2289 Cup
  • 原文地址:https://www.cnblogs.com/tanxing/p/5608608.html
Copyright © 2011-2022 走看看