三向切分的快速排序算法:有大量重复元素的快速排序

        在之前的《快速排序及改进》中,已经对快速排序做了改进;但是在实际的工作环境中,经常会遇到含有大量重复元素的数组,也经常会对这样的数组排序,对这样的数组排序,快速排序性能还可以,但是可以有更大的性能改进,将快速排序的的时间复杂度有对数级提高到线性级别。
        三向切分的快速排序是对快速排序算法改进,特别适用于有大量重复元素的数组的排序,其时间复杂度介于N - NlogN之间,最好的时间复杂度接近于O(N),在没有重复元素的情况下有最坏的时间复杂度,空间复杂度为lgN。
        三向切分的快速排序算法在包括重复元素很多的情况下,要比归并排序和其他排序方法有更好的性能。
        三向切分的快速排序的过程是这样的:从左到右遍历数组一次,维护一个指针lt使得a[lo ... lt - 1]中的元素都小于v,一个指针gt使得a[gt + 1 ... hi]中的元素都大于v,一个指针使得a[lt...i - 1]中的元素都等于v,a[i ... gt]中的元素都还不确定,如下图所示:

        一开始i = lo,使用Comparable接口对a[i]进行三向比较处理:
        1)、a[i]小于v,将a[lt]和a[i]交换,然后将lt和i加一;
        2)、a[i]大于v,将a[gt]和a[i]交换,然后将gt减一;
        3)、a[i]等于v,然后将i加一;
        除非和切分元素相等,其他元素都会被交换。全部代码如下:
        /**
         * 三向切分的快速排序算法:有大量重复元素的快速排序 
         * @author jacky
         *
         */
 public class Quick3waySort extends SortBase{

	    public static void sort(Comparable[] a){
		    //为获得接近于最好的排序性能(最好的时间复杂度),首先将原数组“洗牌"
		    shuffle(a);
		    //开始排序
		    sort(a,0,a.length - 1);
	    }
	
	    /**
	     * 三向切分的快速排序实现
	     * @param a
	     * @param lo
	     * @param hi
	     */
	    private static void sort(Comparable[] a,int lo,int hi){
		    if(hi <= lo) return;
		    int lt = lo;
		    int i = lo + 1;
		    int gt = hi;
		    Comparable v = a[lo];
		    int cmp = 0;
		    while(i <= gt){
			    cmp = a[i].compareTo(v);
			    if(cmp < 0){
				    exch(a,lt++,i++);
			    }else if(cmp > 0){
				    exch(a,i,gt--);
			    }else{
				    i++;
			    }
		    }//现在a[lo ... lt - 1] < v = a[lt ... gt] < a[gt + 1 ... hi]成立
		    sort(a,lo,lt - 1);
		    sort(a,gt + 1,hi);
	    }
 }
        

猜你喜欢

转载自flyingdutchman.iteye.com/blog/1864700
今日推荐