高级排序-快速排序详解

辅助工具

概述

快速排序由C. A. R. Hoare在1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

简单来说, 就是设定一个标准V, 每次遍历就将整个数组分成小于V和大于V的两部分, 这时,V就处于它在排好序的数组中应该在的位置, 然后再对左右两部分分别进行递归排序, 这个将数组分割成两部分的操作, 称之为partition, 下面看下代码实现 :

代码实现

package sort.quick;

import sort.Sort ;
import utils.ArrayUtil ;


public class QuickSort implements Sort {
	
	@Override
	public void sort(int [] arr) {
		quickSort(arr, 0, arr.length - 1);
	}
	
	/**
	 * 对数组arr的[l, r]前闭后闭的区间进行快速排序
	 * 递归方法
	 * @param arr
	 * @param l
	 * @param r
	 */
	private void quickSort(int [] arr, int l, int r){
		// 递归终止条件
		if (l >= r) {
			return;
		}
		
		int p = partition(arr, l, r);
		quickSort(arr, l, p - 1);
		quickSort(arr, p + 1, r);
	}
	
	/**
	 * 对arr数组的前闭后闭区间[l, r]进行partition操作
	 * @param arr
	 * @param l
	 * @param r
	 * @return 返回分割后作为标记元素的下标位置
	 */
	private int partition(int [] arr, int l, int r){
		// 设置用于对比的元素为arr[l]
				int v = arr[l];
				// arr[l + 1, j] <v; arr[j+1, i)>v
				int j = l;
				for (int i = l; i <= r; i++) {
					if (arr[i] < v) {
						ArrayUtil.swap(arr, i, j + 1);
						j++;
					}
				}
				ArrayUtil.swap(arr, l, j);
		return j;
	}
	
}

下面我们就可以测试一下快速排序和归并排序的性能之间的差异, 测试代码如下 :

	/**
	 * 测试插入排序和归并排序性能
	 */
	@Test
	public void testSort(){
		// 生成一个随机数组
		int[] arr = ArrayUtil.generateArray(1000000, 0, 1000000);
		int[] arr1 = ArrayUtil.copyArray(arr);
		int[] arr2 = ArrayUtil.copyArray(arr);
		int[] arr3 = ArrayUtil.copyArray(arr);
		int[] arr4 = ArrayUtil.copyArray(arr);
		System.out.println("----------------------------------随机数组----------------------------------") ;
		System.out.println("归并排序1 : " + ArrayUtil.testSort(arr1, new MergeSort()) + "s") ;
		System.out.println("归并排序2 : " + ArrayUtil.testSort(arr2, new MergeSort2()) + "s") ;
		System.out.println("归并排序3 : " + ArrayUtil.testSort(arr3, new MergeSort3()) + "s") ;
		System.out.println("自底向上的归并排序 : " + ArrayUtil.testSort(arr4, new MergeSortBU()) + "s") ;
		System.out.println("快速排序 : " + ArrayUtil.testSort(arr, new QuickSort()) + "s") ;
		/*
		 * 生成一个近乎有序的数组
		 * 100000 : 数组元素个数
		 * 10 : 在一个完全有序的数组上进行多少次元素交换
		 */
        arr = ArrayUtil.generateNearlyOrderedArray(1000000, 10);
		arr1 = ArrayUtil.copyArray(arr);
		arr2 = ArrayUtil.copyArray(arr);
		arr3 = ArrayUtil.copyArray(arr);
		arr4 = ArrayUtil.copyArray(arr);
		System.out.println("------------------------------近乎有序的数组------------------------------") ;
		System.out.println("归并排序1:" + ArrayUtil.testSort(arr1, new MergeSort()) + "s") ;
		System.out.println("归并排序2:" + ArrayUtil.testSort(arr2, new MergeSort2()) + "s") ;
		System.out.println("归并排序3:" + ArrayUtil.testSort(arr3, new MergeSort3()) + "s") ;
		System.out.println("自底向上的归并排序:" + ArrayUtil.testSort(arr4, new MergeSortBU()) + "s") ;
		System.out.println("快速排序 : " + ArrayUtil.testSort(arr, new QuickSort()) + "s") ;


	      /*
         * 生成一个存在大量重复元素的数组
         * 100000 : 数组元素个数
         */
        arr = ArrayUtil.generateArray(1000000, 0,  100);
        arr1 = ArrayUtil.copyArray(arr);
        arr2 = ArrayUtil.copyArray(arr);
        arr3 = ArrayUtil.copyArray(arr);
        arr4 = ArrayUtil.copyArray(arr);
        System.out.println("------------------------------存在大量重复元素的数组------------------------------") ;
        System.out.println("归并排序1:" + ArrayUtil.testSort(arr1, new MergeSort()) + "s") ;
        System.out.println("归并排序2:" + ArrayUtil.testSort(arr2, new MergeSort2()) + "s") ;
        System.out.println("归并排序3:" + ArrayUtil.testSort(arr3, new MergeSort3()) + "s") ;
        System.out.println("自底向上的归并排序:" + ArrayUtil.testSort(arr4, new MergeSortBU()) + "s") ;
        System.out.println("快速排序 : " + ArrayUtil.testSort(arr, new QuickSort()) + "s") ;

	}

测试结果如下 :

----------------------------------随机数组----------------------------------
归并排序1 : 0.205s
归并排序2 : 0.148s
归并排序3 : 0.154s
自底向上的归并排序 : 0.162s
快速排序 : 0.109s
------------------------------近乎有序的数组------------------------------
归并排序1:0.082s
归并排序2:0.047s
归并排序3:0.016s
自底向上的归并排序:0.02s
快速排序 : 60.363s
------------------------------存在大量重复元素的数组------------------------------
归并排序1:0.154s
归并排序2:0.114s
归并排序3:0.09s
自底向上的归并排序:0.09s
快速排序 : 3.401s

对于100万的数据量, 从上面的测试结果来说, 可以得到下面的结论 :

  • 对于随机数组来说, 快速排序的性能已经高于了归并排序了
  • 对于近乎有序的数组, 由于这个版本的在partition的过程中每次都取第一个元素作为标准, 这会导致partition分割的两部分严重不均衡, 在极端情况下即数组完全有序的情况下, 会退化成O(n²)级别的算法, 所以这个排序花了60多秒, 这个时间显然是不能接受的, 下面会进行优化
  • 对于存在大量重复元素的数组, 上面的代码其实是分成小于等于V和大于V的两部分, 一样是会造成partition的不平衡, 下面是对这些问题的优化方案

需要注意的一点是, 在对近乎有序的数组使用这一版的归并排序时, 会因为递归深度较深而占用大量栈空间, 如果报StackOVerflow的异常, 可以使用参数-Xss将栈空间设置大一点, 我这里设置了-Xss128m是没有问题的

排序优化

优化1

在上一篇归并排序的文章中就说过, 对于数据量较小的数组, 使用插入排序的性能反而更快, 所以可以在partition到底层数据量较小的时候, 使用插入排序替换快速排序, 进行第一次优化 :

package sort.quick;

import sort.Sort ;
import utils.ArrayUtil ;


/**
 * 快速排序优化
 * @author xuxiumeng
 *
 */
public class QuickSort2 implements Sort {
    
    @Override
    public void sort(int [] arr) {
        quickSort(arr, 0, arr.length - 1);
    }
    
    /**
     * 对数组arr的[l, r]前闭后闭的区间进行快速排序
     * 递归方法
     * @param arr
     * @param l
     * @param r
     */
    private void quickSort(int [] arr, int l, int r){
        // 递归终止条件
        if ( r - l < 16) {
            ArrayUtil.insertSort(arr, l, r);
            return;
        }
        
        int p = partition(arr, l, r);
        quickSort(arr, l, p - 1);
        quickSort(arr, p + 1, r);
    }
    
    /**
     * 对arr数组的前闭后闭区间[l, r]进行partition操作
     * @param arr
     * @param l
     * @param r
     * @return 返回分割后作为标记元素的下标位置
     */
    private int partition(int [] arr, int l, int r){
        // 设置用于对比的元素为arr[l]
                int v = arr[l];
                // arr[l + 1, j] <v; arr[j+1, i)>v
                int j = l;
                for (int i = l; i <= r; i++) {
                    if (arr[i] < v) {
                        ArrayUtil.swap(arr, i, j + 1);
                        j++;
                    }
                }
                ArrayUtil.swap(arr, l, j);
        return j;
    }
    
}

测试代码 :

	/**
	 * 测试插入排序和归并排序性能
	 */
	@Test
	public void testSort(){
		// 生成一个随机数组
		int[] arr = ArrayUtil.generateArray(1000000, 0, 1000000);
		int[] arr1 = ArrayUtil.copyArray(arr);
		int[] arr2 = ArrayUtil.copyArray(arr);
		int[] arr3 = ArrayUtil.copyArray(arr);
		int[] arr4 = ArrayUtil.copyArray(arr);
		int[] arr5 = ArrayUtil.copyArray(arr);
		System.out.println("----------------------------------随机数组----------------------------------") ;
		System.out.println("归并排序1 : " + ArrayUtil.testSort(arr1, new MergeSort()) + "s") ;
		System.out.println("归并排序2 : " + ArrayUtil.testSort(arr2, new MergeSort2()) + "s") ;
		System.out.println("归并排序3 : " + ArrayUtil.testSort(arr3, new MergeSort3()) + "s") ;
		System.out.println("自底向上的归并排序 : " + ArrayUtil.testSort(arr4, new MergeSortBU()) + "s") ;
		System.out.println("快速排序 : " + ArrayUtil.testSort(arr, new QuickSort()) + "s") ;
        System.out.println("快速排序2 : " + ArrayUtil.testSort(arr5, new QuickSort2()) + "s") ;

		/*
		 * 生成一个近乎有序的数组
		 * 100000 : 数组元素个数
		 * 10 : 在一个完全有序的数组上进行多少次元素交换
		 */
        arr = ArrayUtil.generateNearlyOrderedArray(1000000, 10);
		arr1 = ArrayUtil.copyArray(arr);
		arr2 = ArrayUtil.copyArray(arr);
		arr3 = ArrayUtil.copyArray(arr);
		arr4 = ArrayUtil.copyArray(arr);
	    arr5 = ArrayUtil.copyArray(arr);
		System.out.println("------------------------------近乎有序的数组------------------------------") ;
		System.out.println("归并排序1:" + ArrayUtil.testSort(arr1, new MergeSort()) + "s") ;
		System.out.println("归并排序2:" + ArrayUtil.testSort(arr2, new MergeSort2()) + "s") ;
		System.out.println("归并排序3:" + ArrayUtil.testSort(arr3, new MergeSort3()) + "s") ;
		System.out.println("自底向上的归并排序:" + ArrayUtil.testSort(arr4, new MergeSortBU()) + "s") ;
		System.out.println("快速排序 : " + ArrayUtil.testSort(arr, new QuickSort()) + "s") ;
        System.out.println("快速排序2 : " + ArrayUtil.testSort(arr5, new QuickSort2()) + "s") ;


	      /*
         * 生成一个存在大量重复元素的数组
         * 100000 : 数组元素个数
         */
        arr = ArrayUtil.generateArray(1000000, 0,  100);
        arr1 = ArrayUtil.copyArray(arr);
        arr2 = ArrayUtil.copyArray(arr);
        arr3 = ArrayUtil.copyArray(arr);
        arr4 = ArrayUtil.copyArray(arr);
        arr5 = ArrayUtil.copyArray(arr);
        System.out.println("------------------------------存在大量重复元素的数组------------------------------") ;
        System.out.println("归并排序1:" + ArrayUtil.testSort(arr1, new MergeSort()) + "s") ;
        System.out.println("归并排序2:" + ArrayUtil.testSort(arr2, new MergeSort2()) + "s") ;
        System.out.println("归并排序3:" + ArrayUtil.testSort(arr3, new MergeSort3()) + "s") ;
        System.out.println("自底向上的归并排序:" + ArrayUtil.testSort(arr4, new MergeSortBU()) + "s") ;
        System.out.println("快速排序 : " + ArrayUtil.testSort(arr, new QuickSort()) + "s") ;
        System.out.println("快速排序2 : " + ArrayUtil.testSort(arr5, new QuickSort2()) + "s") ;


	}

测试结果 :

----------------------------------随机数组----------------------------------
归并排序1 : 0.191s
归并排序2 : 0.143s
归并排序3 : 0.156s
自底向上的归并排序 : 0.16s
快速排序 : 0.109s
快速排序2 : 0.102s
------------------------------近乎有序的数组------------------------------
归并排序1:0.082s
归并排序2:0.047s
归并排序3:0.014s
自底向上的归并排序:0.021s
快速排序 : 134.718s
快速排序2 : 133.616s
------------------------------存在大量重复元素的数组------------------------------
归并排序1:0.183s
归并排序2:0.109s
归并排序3:0.086s
自底向上的归并排序:0.09s
快速排序 : 3.495s
快速排序2 : 3.481s

从测试结果看出, 这一版的快速排序比上一版的快速排序性能上要稍微好一点, 但是并没有借据近乎有序的数组, 和存在大量重复元素的数组性能较差的问题, 所以还需要继续优化

优化2

因为数组可能是近乎有序的数组, 所以我们可以不每次取队首的元素, 一种方案是每次随机取一个元素, 一种方案是取队首, 中间, 队尾三个元素中取大小排在中间的那个, 这里我们就使用随机元素的方案, 代码如下:

package sort.quick;

import java.util.Random;

import sort.Sort ;
import utils.ArrayUtil ;


/**
 * 快速排序优化
 * 上面两个版本的快速排序, 在处理近乎有序的数组的时候,性能很差, 
 * 因为每次partition时都取队首元素, 在数组近乎有序的时候, 会导致partition的两部分很不均匀
 * 在数组完全有序的情况下, 快速排序甚至会退化成O(n²)算法
 * 优化方案 : 每次随机取一个元素, 而不是每次取第一个元素
 * @author xuxiumeng
 *
 */
public class QuickSort3 implements Sort {
  private static Random random = new Random();
  
    @Override
    public void sort(int [] arr) {
        quickSort(arr, 0, arr.length - 1);
    }
    
    /**
     * 对数组arr的[l, r]前闭后闭的区间进行快速排序
     * 递归方法
     * @param arr
     * @param l
     * @param r
     */
    private void quickSort(int [] arr, int l, int r){
        // 递归终止条件
        if ( r - l < 16) {
            ArrayUtil.insertSort(arr, l, r);
            return;
        }
        
        int p = partition(arr, l, r);
        quickSort(arr, l, p - 1);
        quickSort(arr, p + 1, r);
    }
    
    /**
     * 对arr数组的前闭后闭区间[l, r]进行partition操作
     * @param arr
     * @param l
     * @param r
     * @return 返回分割后作为标记元素的下标位置
     */
    private int partition(int [] arr, int l, int r){
        // 获取用于对比的随机元素下标
        int randomNum = random.nextInt(r - l) + l;
        ArrayUtil.swap(arr, l, randomNum);
        // 设置用于对比的元素为arr[l]
        int v = arr[l];
        // arr[l + 1, j] <v; arr[j+1, i)>v
        int j = l;
        for (int i = l; i <= r; i++) {
            if (arr[i] < v) {
                ArrayUtil.swap(arr, i, j + 1);
                j++;
            }
        }
        ArrayUtil.swap(arr, l, j);
        return j;
    }
    
}

相比上一版, 这一版在排序的过程中仅仅多了如下两行代码 :

        // 获取用于对比的随机元素下标
        int randomNum = random.nextInt(r - l) + l;
        ArrayUtil.swap(arr, l, randomNum);

测试代码 :

	/**
	 * 测试插入排序和归并排序性能
	 */
	@Test
	public void testSort(){
		// 生成一个随机数组
		int[] arr = ArrayUtil.generateArray(1000000, 0, 1000000);
		int[] arr1 = ArrayUtil.copyArray(arr);
		int[] arr2 = ArrayUtil.copyArray(arr);
		int[] arr3 = ArrayUtil.copyArray(arr);
		int[] arr4 = ArrayUtil.copyArray(arr);
		int[] arr5 = ArrayUtil.copyArray(arr);
		int[] arr6 = ArrayUtil.copyArray(arr);
//		int[] arr7 = ArrayUtil.copyArray(arr);
		System.out.println("----------------------------------随机数组----------------------------------") ;
		System.out.println("归并排序1 : " + ArrayUtil.testSort(arr1, new MergeSort()) + "s") ;
		System.out.println("归并排序2 : " + ArrayUtil.testSort(arr2, new MergeSort2()) + "s") ;
		System.out.println("归并排序3 : " + ArrayUtil.testSort(arr3, new MergeSort3()) + "s") ;
		System.out.println("自底向上的归并排序 : " + ArrayUtil.testSort(arr4, new MergeSortBU()) + "s") ;
		System.out.println("快速排序 : " + ArrayUtil.testSort(arr, new QuickSort()) + "s") ;
        System.out.println("快速排序2 : " + ArrayUtil.testSort(arr5, new QuickSort2()) + "s") ;
        System.out.println("快速排序3 : " + ArrayUtil.testSort(arr6, new QuickSort3()) + "s") ;
//        System.out.println("三路快速排序 : " + ArrayUtil.testSort(arr7, new QuickSort3Ways()) + "s") ;

		/*
		 * 生成一个近乎有序的数组
		 * 100000 : 数组元素个数
		 * 10 : 在一个完全有序的数组上进行多少次元素交换
		 */
        arr = ArrayUtil.generateNearlyOrderedArray(1000000, 10);
		arr1 = ArrayUtil.copyArray(arr);
		arr2 = ArrayUtil.copyArray(arr);
		arr3 = ArrayUtil.copyArray(arr);
		arr4 = ArrayUtil.copyArray(arr);
	    arr5 = ArrayUtil.copyArray(arr);
	    arr6 = ArrayUtil.copyArray(arr);
//	    arr7 = ArrayUtil.copyArray(arr);
		System.out.println("------------------------------近乎有序的数组------------------------------") ;
		System.out.println("归并排序1:" + ArrayUtil.testSort(arr1, new MergeSort()) + "s") ;
		System.out.println("归并排序2:" + ArrayUtil.testSort(arr2, new MergeSort2()) + "s") ;
		System.out.println("归并排序3:" + ArrayUtil.testSort(arr3, new MergeSort3()) + "s") ;
		System.out.println("自底向上的归并排序:" + ArrayUtil.testSort(arr4, new MergeSortBU()) + "s") ;
		System.out.println("快速排序 : " + ArrayUtil.testSort(arr, new QuickSort()) + "s") ;
        System.out.println("快速排序2 : " + ArrayUtil.testSort(arr5, new QuickSort2()) + "s") ;
        System.out.println("快速排序3 : " + ArrayUtil.testSort(arr6, new QuickSort3()) + "s") ;
//        System.out.println("三路快速排序 : " + ArrayUtil.testSort(arr7, new QuickSort3Ways()) + "s") ;

	      /*
         * 生成一个存在大量重复元素的数组
         * 100000 : 数组元素个数
         */
        arr = ArrayUtil.generateArray(1000000, 0,  100);
        arr1 = ArrayUtil.copyArray(arr);
        arr2 = ArrayUtil.copyArray(arr);
        arr3 = ArrayUtil.copyArray(arr);
        arr4 = ArrayUtil.copyArray(arr);
        arr5 = ArrayUtil.copyArray(arr);
        arr6 = ArrayUtil.copyArray(arr);
//        arr7 = ArrayUtil.copyArray(arr);
        System.out.println("------------------------------存在大量重复元素的数组------------------------------") ;
        System.out.println("归并排序1:" + ArrayUtil.testSort(arr1, new MergeSort()) + "s") ;
        System.out.println("归并排序2:" + ArrayUtil.testSort(arr2, new MergeSort2()) + "s") ;
        System.out.println("归并排序3:" + ArrayUtil.testSort(arr3, new MergeSort3()) + "s") ;
        System.out.println("自底向上的归并排序:" + ArrayUtil.testSort(arr4, new MergeSortBU()) + "s") ;
        System.out.println("快速排序 : " + ArrayUtil.testSort(arr, new QuickSort()) + "s") ;
        System.out.println("快速排序2 : " + ArrayUtil.testSort(arr5, new QuickSort2()) + "s") ;
        System.out.println("快速排序3 : " + ArrayUtil.testSort(arr6, new QuickSort3()) + "s") ;
//        System.out.println("三路快速排序 : " + ArrayUtil.testSort(arr7, new QuickSort3Ways()) + "s") ;

	}

测试结果 :

----------------------------------随机数组----------------------------------
归并排序1 : 0.189s
归并排序2 : 0.142s
归并排序3 : 0.144s
自底向上的归并排序 : 0.15s
快速排序 : 0.115s
快速排序2 : 0.095s
快速排序3 : 0.099s
------------------------------近乎有序的数组------------------------------
归并排序1:0.082s
归并排序2:0.048s
归并排序3:0.016s
自底向上的归并排序:0.023s
快速排序 : 89.75s
快速排序2 : 83.944s
快速排序3 : 0.032s
------------------------------存在大量重复元素的数组------------------------------
归并排序1:0.177s
归并排序2:0.096s
归并排序3:0.088s
自底向上的归并排序:0.09s
快速排序 : 2.99s
快速排序2 : 2.803s
快速排序3 : 3.454s

可以看到仅仅多了两行代码, 这种情况下对于近乎有序的数组的排序性能提高了很多, 只是对于存在大量重复元素的数组, 排序性能还需要进一步进行优化

优化3 : 三路快排

对于存在大量重复元素的数组, 我们可以不仅仅将数组分割成两部分, 而是可以将数组分割成小于V, 等于V, 大于V的三部分, 然后对小于V和大于V的两部分在进行递归排序, 代码如下:

package sort.quick;

import java.util.Random;

import sort.Sort ;
import utils.ArrayUtil ;


/**
 * 快速排序优化
 * 上面快速排序的三个版本仍然存在一定的问题, 对于存在大量重复元素的数组, 
 * 排序的性能是远远低于归并排序的, 
 * 原因是因为每次进行partition实际是把数组分成小于等于v的元素和大于v的元素, 由于存在大量重复的元素
 * 所以会导致partition分割的两部分很不平衡
 * 
 * 优化方案 : 三路快排, 将数组分割成大于V,等于V, 小于V的三部分
 * @author xuxiumeng
 *
 */
public class QuickSort3Ways implements Sort {
  private static Random random = new Random();
  
    @Override
    public void sort(int [] arr) {
      quickSort3Ways(arr, 0, arr.length - 1);
    }
    
    /**
     * 对数组arr的[l, r]前闭后闭的区间进行快速排序
     * 递归方法
     * @param arr
     * @param l
     * @param r
     */
    private void quickSort3Ways(int [] arr, int l, int r){
        // 递归终止条件
        if ( r - l < 16) {
            ArrayUtil.insertSort(arr, l, r);
            return;
        }
        
        // 获取用于对比的随机元素下标
        int randomNum = random.nextInt(r - l) + l;
        ArrayUtil.swap(arr, l, randomNum);
        // 设置用于对比的元素为arr[l]
        int v = arr[l];
        
        // 设定arr[l+1...lt] < v, 初始情况下这个区间为空, 默认符合这个定义
        int lt = l; 
        // 设定arr[gt...r] > v, 初始情况下这个区间为空, 默认符合这个定义
        int gt = r + 1; 
        // arr[lt+1...i) == v, 初始情况下这个区间为空, 默认符合这个定义
        int i = l+1;
        // 在整个遍历过程中都保持arr[l+1...lt] < v, arr[gt...r] > v, arr[lt+1...i) == v
        while (i < gt) {
          if (arr[i] < v ) {
            ArrayUtil.swap(arr, i, lt + 1);
            lt++;
            i++;
           
          } else if (arr[i] > v) {
            // 这种情况下i的位置是从gt-1交换过来的元素, 仍然需要对这个元素进行判断, 所以这里不需要i++;
            ArrayUtil.swap(arr, i, gt - 1);
            gt--;
          } else {
            i++;
          }
        }
        
        ArrayUtil.swap(arr, l, lt);
        
        quickSort3Ways(arr, l, lt - 1);
        quickSort3Ways(arr, gt, r);
    }
    
}

测试代码 :

	/**
	 * 测试插入排序和归并排序性能
	 */
	@Test
	public void testSort(){
		// 生成一个随机数组
		int[] arr = ArrayUtil.generateArray(1000000, 0, 1000000);
		int[] arr1 = ArrayUtil.copyArray(arr);
		int[] arr2 = ArrayUtil.copyArray(arr);
		int[] arr3 = ArrayUtil.copyArray(arr);
		int[] arr4 = ArrayUtil.copyArray(arr);
		int[] arr5 = ArrayUtil.copyArray(arr);
		int[] arr6 = ArrayUtil.copyArray(arr);
		int[] arr7 = ArrayUtil.copyArray(arr);
		System.out.println("----------------------------------随机数组----------------------------------") ;
		System.out.println("归并排序1 : " + ArrayUtil.testSort(arr1, new MergeSort()) + "s") ;
		System.out.println("归并排序2 : " + ArrayUtil.testSort(arr2, new MergeSort2()) + "s") ;
		System.out.println("归并排序3 : " + ArrayUtil.testSort(arr3, new MergeSort3()) + "s") ;
		System.out.println("自底向上的归并排序 : " + ArrayUtil.testSort(arr4, new MergeSortBU()) + "s") ;
		System.out.println("快速排序 : " + ArrayUtil.testSort(arr, new QuickSort()) + "s") ;
        System.out.println("快速排序2 : " + ArrayUtil.testSort(arr5, new QuickSort2()) + "s") ;
        System.out.println("快速排序3 : " + ArrayUtil.testSort(arr6, new QuickSort3()) + "s") ;
        System.out.println("三路快速排序 : " + ArrayUtil.testSort(arr7, new QuickSort3Ways()) + "s") ;

		/*
		 * 生成一个近乎有序的数组
		 * 100000 : 数组元素个数
		 * 10 : 在一个完全有序的数组上进行多少次元素交换
		 */
        arr = ArrayUtil.generateNearlyOrderedArray(1000000, 10);
		arr1 = ArrayUtil.copyArray(arr);
		arr2 = ArrayUtil.copyArray(arr);
		arr3 = ArrayUtil.copyArray(arr);
		arr4 = ArrayUtil.copyArray(arr);
	    arr5 = ArrayUtil.copyArray(arr);
	    arr6 = ArrayUtil.copyArray(arr);
	    arr7 = ArrayUtil.copyArray(arr);
		System.out.println("------------------------------近乎有序的数组------------------------------") ;
		System.out.println("归并排序1:" + ArrayUtil.testSort(arr1, new MergeSort()) + "s") ;
		System.out.println("归并排序2:" + ArrayUtil.testSort(arr2, new MergeSort2()) + "s") ;
		System.out.println("归并排序3:" + ArrayUtil.testSort(arr3, new MergeSort3()) + "s") ;
		System.out.println("自底向上的归并排序:" + ArrayUtil.testSort(arr4, new MergeSortBU()) + "s") ;
		System.out.println("快速排序 : " + ArrayUtil.testSort(arr, new QuickSort()) + "s") ;
        System.out.println("快速排序2 : " + ArrayUtil.testSort(arr5, new QuickSort2()) + "s") ;
        System.out.println("快速排序3 : " + ArrayUtil.testSort(arr6, new QuickSort3()) + "s") ;
        System.out.println("三路快速排序 : " + ArrayUtil.testSort(arr7, new QuickSort3Ways()) + "s") ;

	      /*
         * 生成一个存在大量重复元素的数组
         * 100000 : 数组元素个数
         */
        arr = ArrayUtil.generateArray(1000000, 0,  100);
        arr1 = ArrayUtil.copyArray(arr);
        arr2 = ArrayUtil.copyArray(arr);
        arr3 = ArrayUtil.copyArray(arr);
        arr4 = ArrayUtil.copyArray(arr);
        arr5 = ArrayUtil.copyArray(arr);
        arr6 = ArrayUtil.copyArray(arr);
        arr7 = ArrayUtil.copyArray(arr);
        System.out.println("------------------------------存在大量重复元素的数组------------------------------") ;
        System.out.println("归并排序1:" + ArrayUtil.testSort(arr1, new MergeSort()) + "s") ;
        System.out.println("归并排序2:" + ArrayUtil.testSort(arr2, new MergeSort2()) + "s") ;
        System.out.println("归并排序3:" + ArrayUtil.testSort(arr3, new MergeSort3()) + "s") ;
        System.out.println("自底向上的归并排序:" + ArrayUtil.testSort(arr4, new MergeSortBU()) + "s") ;
        System.out.println("快速排序 : " + ArrayUtil.testSort(arr, new QuickSort()) + "s") ;
        System.out.println("快速排序2 : " + ArrayUtil.testSort(arr5, new QuickSort2()) + "s") ;
        System.out.println("快速排序3 : " + ArrayUtil.testSort(arr6, new QuickSort3()) + "s") ;
        System.out.println("三路快速排序 : " + ArrayUtil.testSort(arr7, new QuickSort3Ways()) + "s") ;

	}

测试结果 :

----------------------------------随机数组----------------------------------
归并排序1 : 0.197s
归并排序2 : 0.137s
归并排序3 : 0.163s
自底向上的归并排序 : 0.143s
快速排序 : 0.107s
快速排序2 : 0.102s
快速排序3 : 0.109s
三路快速排序 : 0.13s
------------------------------近乎有序的数组------------------------------
归并排序1:0.09s
归并排序2:0.05s
归并排序3:0.019s
自底向上的归并排序:0.026s
快速排序 : 92.938s
快速排序2 : 87.269s
快速排序3 : 0.035s
三路快速排序 : 0.064s
------------------------------存在大量重复元素的数组------------------------------
归并排序1:0.167s
归并排序2:0.092s
归并排序3:0.088s
自底向上的归并排序:0.088s
快速排序 : 3.503s
快速排序2 : 3.389s
快速排序3 : 2.252s
三路快速排序 : 0.036s

从测试结果来看, 三路快排基本上解决了各种问题, 虽然在对随机数组排序的性能上比之前几种稍差一点, 但是完全是在能接受的范围内, 影响不大

总结

  • O(nlogn)级别算法
  • 非稳定性算法, 算法稳定性可以参见上一篇递归排序里面的定义
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值