快速排序的两种实现

快速排序是一种非常高效的基于比较的排序算法,其能在O(NlogN)的时间复杂度内完成排序。当然,这是期望运行时间,实际上也可能是O(N^2)。这取决与算法划分的是否平衡。快速排序算法的实现过程依赖于分治思想,按照分解、解决、合并的一般步骤看的话,快排实际上只用到了分解和解决两个步骤,因为快排是原址的,所以当合并的时候,排序的元素已经是有序状态了。

版本一

/** * desc : 快速排序 * Created by tiantian on 2018/7/31 */
public class QuickSort {

    public void quickSort(Integer[] array, int p, int r) {
        if (p < r) {
            int q = partition(array, p, r);
            quickSort(array, p, q-1);
            quickSort(array, q+1, r);
        }
    }

    public int partition(Integer[] array, int p, int r) {
        Integer pivot = array[r];
        int i = p - 1;
        for (int j = p; j < r; j++) {
            if (array[j] <= pivot) {
                i++;
                this.exchange(array, i, j);
            }
        }
        this.exchange(array, i+1, r);

        return i+1;
    }

    public void exchange(Integer[] array, int a, int b) {
        Integer temp = array[a];
        array[a] = array[b];
        array[b] = temp;
    }
}

quickSort方法先是调用partition方法完成划分任务。然后分别两次调用自身完成解决。第二次调用自身其实不是必须的,也可以以循环的方式调用。partition方法是该排序至关重要的方法。它以最后每次划分的最后一个元素为参照,即下标为r的元素。然后比较参照元素pivot和array[j],如果小于pivot,则交换顺序。每次的交换结果是:以i为界,大于pivot的元素在i的右侧,反之。直到遍历终止的时候这这种状态依然保持,所以从算法的正确性亦毋庸置疑。

版本二

版本二的实现是版本一的加强。版本一pivot(参照元素,专业的说法是主元)元素的选择是每次划分的数组的最后一个元素。而加强版的算法实现partition方法划分数组时是在下标为p到r的元素之间随机选择一个作为主元参与比较。这样做的原因是前面所说的,划分的平衡性的考虑。

/** * desc : 随机化的快速排序 * Created by tiantian on 2018/8/2 */
public class RandomizedQuickSort {

    public void randomizedQuickSort(Integer[] array, int p, int r) {
        if (p < r) {
            int q = randomizedPartition(array, p, r);
            this.randomizedQuickSort(array, p, q-1);
            this.randomizedQuickSort(array, q+1, r);
        }
    }

    public int randomizedPartition(Integer[] array, int p, int r) {
        int random = this.randomNum(p, r);
        this.exchange(array, random, r);
        Integer pivot = array[r];
        int i = p-1;
        for (int j = p; j < r; j++) {
            if (array[j] <= pivot) {
                i++;
                this.exchange(array, i, j);
            }
        }
        this.exchange(array,i+1, r);
        return i+1;
    }

    public void exchange(Integer[] array, int a, int b) {
        Integer temp = array[a];
        array[a] = array[b];
        array[b] = temp;
    }


    public int randomNum(int i, int j) {
        Random random = new Random();
        return random.nextInt(j-i) + i;
    }

    public static void main(String[] args) {
        Integer[] testArray = new Integer[100000];
        int len = testArray.length;
        Random random = new Random();
        for (int i = 0; i < len; i++) {
            testArray[i] = random.nextInt(100000);
        }

        for (int i = 0; i < len; i++) {
// System.out.print(testArray[i] + " ");
        }


        long start = System.currentTimeMillis();

        RandomizedQuickSort qs = new RandomizedQuickSort();
        qs.randomizedQuickSort(testArray, 0, testArray.length-1);
        long end = System.currentTimeMillis();

        System.out.println("排序结果");
        for (Integer i : testArray) {
            System.err.print(i+" <");
        }

        long time = end - start;
        //System.out.print("排序耗时:" + String.valueOf(time));
    }
}

以下为十万个整数为测试数据的排序结果。由于数据量太多,只展示了首尾数据。感兴趣的朋友可以自己测试。

排序结果
0 <4 <5 <6 <7 <8 <9 <12 <15 <16 <17 <19 <20 <21 <21 <22 <25 <25 <25 <26 <27 <28 <30 <30 <31 <31 <32 <32 <38 <38 <38 <39 <39 <40 <41 <42 <42 <43 <45 <45 <46 <46 <49 <50 <51 <51 <51 <51 <52 <52 <52 <52 <53 <53 <54 <56 <56 <56 <59 <60 <61 <61 <62 <62 <63 <64 <67 <67 <68 <68 <69 <74 <75 <76 <76 <78 <78 <78 <78 <79 <79 <79 <81 <81 <82 <83 <83 <84 <84 <85 <85 <85 <87 <88 <89 <89 <90 <90 <90 <91 <92 <95 <96 <97 <97 <99 <100 <103 <103 <104 <106 <112 <115 <115 <116 <116 <116 <118 <118 <119 <121 <121 <123 <124 <124 <126 <126 <126 <127 <129 <129 <129 <132 <134 <135 <137 <139 <139 <139 <141 <141 <142 <142 <142 <145 <145 <146 <146 <146 <151 <151 <152 <152 <153 <154 <154 <154 <154 <154 <157 <158 <159 <159 <159 <159 <163 <163 <164 <166 <168 <170 <172 <172 <172 <173 <174 <175 <176 <177 <177 <178 <179 <179 <179 <179 <184 <184 <184 <184 <188 <188 <189 <191 <193 <195 <195 <196 <196 <198 <198 <198 <198 <199 <199 <201 <201 <202 <205 <207 <207 <208 <209 <212 <213 <214 <214 <215 <217 <217 <218 <218 <218 <220 <221 <221 <221 <222 <224 <226 <227 <227 <227 <228 <228 <229 <230 <230 <231 <231 <232 <233 <233 <233 <233 <234 <235 <235 <235 <236 <236 <236 <238 <238 <239 <239 <239 <240 <240 <240 <241 <241 <242 <242 <242 <243 <243 <245 <246 <246 <246 <247 <249 <250 <250 <251 <253 <255 <257 <257 <257 <260 <262 <262 <264 <265 <267 <268 <268 <268 <269 <270 <274 <274 <275 <275 <276 <276 <277 <278 <279 <279 <281 <281 <281 <284 <286 <288 <290 <291 <292 <295 <295 <296 <298 <298 <300 <301 <302 <305 <306 <306 <306 <308 <309 <310 <311 <312 <312 <312 <316 <316 <319 <322 <322 <322 <322 <324 <324 <327 <329 <329 <329 <330 <330 <331 <332 <332 <333 <333 <334 <337 <337 <338 <339 <340 <341 <342 <343 <344 <344 <345 <345 <346 <349 <349 <351 <352 <353 <354 <354 <354 <354 <357 <361 <361 <362 <364 <365 <366 <369 <370 <370 <371 <376 <376 <377 <377 <377 <378 <380 <381 <383 <384 <386 <388 <388 <388 <388 <389 <389 <390 <392 <393 <395 <395 <397 <397 <398 <398 <399 <400 <400 <400 <401 <402 <402 <406 <408 <408 <408 <408 <410 <410 <412 <413 <414 <415 <415 <416 <420 <420 <420 <422 <423 <425 <426 <427 <427 <427 <430 <431 <433 ... 99641 <99642 <99644 <99645 <99646 <99646 <99646 <99647 <99648 <99649 <99652 <99653 <99656 <99660 <99660 <99661 <99662 <99664 <99665 <99666 <99666 <99666 <99667 <99669 <99669 <99670 <99670 <99671 <99671 <99672 <99673 <99675 <99675 <99678 <99679 <99681 <99681 <99681 <99684 <99685 <99686 <99686 <99686 <99687 <99687 <99687 <99687 <99690 <99690 <99691 <99693 <99693 <99693 <99693 <99693 <99694 <99694 <99694 <99696 <99698 <99699 <99700 <99701 <99701 <99702 <99703 <99704 <99704 <99704 <99704 <99705 <99706 <99706 <99709 <99709 <99709 <99710 <99711 <99711 <99711 <99712 <99713 <99713 <99714 <99719 <99719 <99719 <99720 <99721 <99721 <99721 <99721 <99722 <99724 <99726 <99729 <99729 <99729 <99730 <99730 <99732 <99732 <99732 <99733 <99734 <99734 <99737 <99738 <99740 <99740 <99742 <99742 <99742 <99743 <99745 <99746 <99746 <99746 <99749 <99750 <99752 <99753 <99753 <99754 <99756 <99756 <99756 <99756 <99757 <99759 <99759 <99762 <99763 <99764 <99765 <99765 <99765 <99766 <99767 <99768 <99769 <99769 <99773 <99775 <99775 <99776 <99776 <99777 <99777 <99778 <99778 <99780 <99780 <99781 <99781 <99782 <99782 <99782 <99782 <99782 <99785 <99785 <99785 <99786 <99787 <99788 <99788 <99788 <99789 <99790 <99791 <99791 <99792 <99792 <99793 <99794 <99796 <99796 <99798 <99798 <99799 <99800 <99802 <99802 <99803 <99804 <99806 <99806 <99808 <99809 <99809 <99810 <99811 <99812 <99813 <99814 <99815 <99816 <99816 <99817 <99817 <99817 <99820 <99820 <99823 <99823 <99824 <99825 <99826 <99827 <99831 <99832 <99833 <99834 <99834 <99835 <99835 <99835 <99836 <99837 <99839 <99840 <99840 <99840 <99840 <99840 <99842 <99842 <99843 <99845 <99845 <99845 <99847 <99848 <99848 <99848 <99850 <99851 <99853 <99854 <99854 <99857 <99858 <99861 <99862 <99863 <99864 <99865 <99866 <99867 <99868 <99868 <99868 <99868 <99870 <99871 <99871 <99871 <99871 <99872 <99873 <99874 <99875 <99876 <99876 <99877 <99880 <99880 <99881 <99881 <99881 <99883 <99884 <99885 <99889 <99889 <99890 <99891 <99892 <99893 <99896 <99896 <99897 <99897 <99898 <99902 <99902 <99902 <99904 <99905 <99905 <99908 <99909 <99910 <99912 <99914 <99915 <99916 <99917 <99917 <99919 <99921 <99922 <99924 <99924 <99924 <99926 <99928 <99928 <99930 <99930 <99934 <99934 <99935 <99935 <99936 <99937 <99940 <99942 <99944 <99945 <99945 <99946 <99946 <99947 <99947 <99949 <99950 <99950 <99951 <99953 <99953 <99955 <99955 <99955 <99957 <99961 <99962 <99962 <99962 <99963 <99964 <99964 <99968 <99969 <99970 <99971 <99972 <99973 <99974 <99974 <99974 <99975 <99975 <99977 <99978 <99979 <99979 <99982 <99984 <99984 <99985 <99986 <99987 <99987 <99988 <99989 <99990 <99990 <99992 <99992 <99993 <99994 <99994 <99995 <99995 <99997 <99998 <99998 <99999

在MacO电脑上测试所用时间平均不超过100毫秒。同样数量的数据换用插入排序测得的结果是20多秒。算法的性能差异显而易见。

点赞