第二届排序算法性能大赛(决赛:希尔排序,堆排序,快速排序,归并排序)

1️⃣参赛选手总览

前四组参赛选手:

👉第一组:插入排序,希尔排序
👉第二组:选择排序,堆排序
👉第三组:冒泡排序,快速排序(划重点)
👉第四组:归并排序

前面几篇博客重点讲解了以下的排序的内容,以及优化过程和性能分析。

到这里,有四位参赛选手最后进入总决赛。他们分别是希尔排序 堆排序 快速排序 归并排序。后面分析总结他们的特性,比较他们的性能。

2️⃣特性总结

时间复杂度和空间复杂度

分类总结

3️⃣性能比较

这里比较的都是对应排序的最佳版本,为了展现最佳性能。

测试使用的类:

/**
 * 排序的辅助类
 * 生成测试数组以及对排序算法进行测试
 **/
public class SortHelper {
    // 获取随机数的对象
    private static final ThreadLocalRandom random = ThreadLocalRandom.current();
    
    //在[left...right]上生成n个随机数
    public static int[] generateRandomArray(int n,int left,int right) {
        int[] arr = new int[n];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = random.nextInt(left,right);
        }
        return arr;
    }

    /**
     * 生成一个大小为n的近乎有序的数组
     * @param n
     * @param times 交换的次数,次数越小越有序,次数越大越无序
     * @return
     */
    public static int[] generateSoredArray(int n,int times) {
        int[] arr = new int[n];
        for (int i = 0; i < n; i++) {
            arr[i] = i;
        }
        // 交换部分元素,交换次数越小,越有序
        for (int i = 0; i < times; i++) {
            // 生成一个在[0..n]上的随机数
            int a = random.nextInt(n);
            int b = random.nextInt(n);
            int temp = arr[a];
            arr[a] = arr[b];
            arr[b] = temp;
        }
        return arr;
    }
    // 根据传入的方法名称就能调用这个方法,需要借助反射
    // 根据方法名称调用相应的排序方法对arr数组进行排序操作
    public static void testSort(String sortName,int[] arr) {
        Class<SevenSort> cls = SevenSort.class;
        try {
            Method method = cls.getDeclaredMethod(sortName,int[].class);
            long start = System.nanoTime();
            method.invoke(null,arr);
            long end = System.nanoTime();
            if (isSorted(arr)) {
                // 算法正确
                System.out.println(sortName + "排序结束,共耗时:" + (end - start) / 1000000.0 + "ms");
            }
        } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    // 生成一个arr的深拷贝数组
    // 为了测试不同排序算法的性能,需要在相同的数据集上进行测试
    public static int[] arrCopy(int[] arr) {
        return Arrays.copyOf(arr,arr.length);
    }

    public static boolean isSorted(int[] arr) {
        for (int i = 0; i < arr.length - 1; i++) {
            if (arr[i] > arr[i + 1]) {
                System.err.println("sort error");
                return false;
            }
        }
        return true;
    }
}

一千万个随机数据

public static void main(String[] args) {
    int n = 10000000;
    int[] arr = SortHelper.generateRandomArray(n, 0, Integer.MAX_VALUE);
    int[] arrCopy4 = SortHelper.arrCopy(arr);
    int[] arrCopy6 = SortHelper.arrCopy(arr);
    int[] arrCopy7 = SortHelper.arrCopy(arr);
    int[] arrCopy10 = SortHelper.arrCopy(arr);
    
    SortHelper.testSort("shellSort", arrCopy4);
    SortHelper.testSort("mergeSortVersion2", arrCopy6);
    SortHelper.testSort("quickSort", arrCopy7);
    SortHelper.testSort("heapSort", arrCopy10);

}

归并排序第二种写法,也就是在一开始就定义和原数据一样大的空间。
快速排序使用的是单路快排,在排序大量的随机数据时,性能是很好的。
而且都在小区间上使用插入排序,尽可能地提升性能。
至于希尔排序和堆排序鉴于算法的原因,所以没有太大的优化空间。

运行结果:

可以看出归并排序和快速排序在此时性能是很好的。

一千万个大量重复数据

int n = 10000000;
int[] arr = SortHelper.generateRandomArray(n,0, 1000);

因为有大量的重复元素,所以不能使用单路快排了,性能衰减,这里换上对大量重复数据排序最有利三路快排,它可以分区一次就把和基准值相同的元素排好,并放在最终的位置上。

运行结果:

由于快排使用了最有利的算法,所以它的性能还是最好的。

一千万个接近有序数据

int[] arr = SortHelper.generateSoredArray(n,1000);

对于这种数据,快排的挖坑法就特别有优势了,因为很多数据都已经有序了,只需要将那些被打乱的数据排序即可,而且挖坑法没有频繁的交换元素,只是将数据赋值,更多的是填坑的过程。

运行结果:

所以对于有些数据,快排的性能会衰减,但是都有相应的算法去解决,所以论速度,快排是当之无愧的。

至于其他的三个排序,性能都比较稳定,如果数据多变的情况下,使用他们也不失为一种好选择。而且归并排序无论在何时都接近快排的性能,并且它还能实现外排序。

在所有的分区设计的排序算法中,都不能保证数据的稳定性,想要数据稳定,还得依靠其他的排序算法。
所以,追求性能的同时,可能会带来一定的弊端,对于不同的场景,选择合适的排序算法,才是正解。

相较于第一届用c代码写的排序大赛,java版本提供了更多的方法和优化思路,同时代码的质量也得到提升。

最后再一次恭喜快排获得冠军

🌸 🌸

4️⃣全部源码

需要源码的小伙伴点击以下传送门
👇
🌀排序源码完整版🌀

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bruin_du

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值