• 排序算法杂谈(一) —— 量化数组的有序程度


    1. 基本有序

    在众多排序算法中,有一个概念被多次提及:数组基本有序。

    例如:

    • 直接插入排序(Insertion Sort)在面对数组基本有序时,体现出良好的性能。
    • 平滑排序(Smooth Sort)在数组趋向有序时,其时间复杂度趋向于 O(n)。
    • 快速排序(Quick Sort)和堆排序(Heap Sort),在面对基本有序的数组时,并不会对其排序的速度有所增长。

    正是由于这个性质,使得直接插入排序,相比于时间复杂度同为 O(n^2) 的冒泡排序(Bubble Sort),拥有了更多的使用场景:

    • 希尔排序(Shell Sort)优化直接插入排序的基础。
    • 归并排序(Merge Sort)在合并小规模的数组时,采取直接插入排序来优化效率。

    那么现在问题就来了:

    • 如何去评价“基本有序”这个词?
    • 如果现在有两个数组,哪一个是相对来说更加有序的?
    • 有没有方法去量化这个特性?

    2. 逆序对(Inversion)

    https://en.wikipedia.org/wiki/Inversion_(discrete_mathematics)

    在数学上,有一个被称之为“逆序对”的性质,它可以用来量化数组的有序程度,定义如下:

    对于数组 A,如果存在正整数 i 和 j,且 i < j,存在 A[i] > A[j]。

    那么数字对 <i, j> 或 <A[i], A[j]> 可以称之为数组 A 的一个逆序对。

    例如:

    对于数组 A = {4, 2, 3},<4, 2> 和 <4, 3> 都是这个数组的逆序对,数组 A 的逆序对个数为 2。

    对于数组 B = {4, 3, 2},<4, 2>,<4, 3> 和 <3, 2> 都是这个数组的逆序对,数组 B 的逆序对个数为 3。

    那么我们可以称:数组 A 比 数组 B 更加有序。

    计算逆序对的代码:

        public static int calculateInversion(int[] array) {
            int counter = 0;
            for (int i = 0; i < array.length - 1; ++i) {
                for (int j = i + 1; j < array.length; ++j) {
                    if (array[i] > array[j]) {
                        counter++;
                    }
                }
            }
            return counter;
        }
    

    3. 希尔排序和梳排序(Comb Sort)的优化原因

    冒泡排序和直接插入排序,在众多时间复杂度为 O(n^2) 的算法中,也是最低效的一类。

    其根本原因在于:排序过程中的每一次交换/移位,只能使原数组的逆序对个数减 1。

    例如:

    数组 A = { 1, 3, 4, 2 } ,针对元素 2 进行直接插入排序。

    • 排序前:A = { 1, 3, 4, 2 },Inversion = 2。
    • 排序过程中,整个数组进行了 2 次移位操作。
    • 排序后:A = { 1, 2, 3, 4 },Inversion = 0。

    而在希尔排序中,每一次的移位操作,会带来更多的逆序对个数减少。

    例如,利用之前介绍希尔排序时的例子: http://www.cnblogs.com/jing-an-feng-shao/p/6169690.html

    数组 A = { 89, 45, 54, 29, 90, 34, 68 },初始增量 gap = 3。

    • 排序前:A = { 89, 45, 54, 29, 90, 34, 68 },Inversion = 10。
    • 排序过程中,整个数组进行了 2 次移位操作。
    • 排序后:A = { 29, 45, 34, 68, 90, 54, 89 },Inversion = 4。

    所以说,在这个案例中,希尔排序利用 2 次移位操作,消除了 6 对逆序对,从而提高了整体的算法效率。

    梳排序中同样引进了 gap 的概念,增加了冒泡排序的算法效率。

  • 相关阅读:
    java 实现敏感词(sensitive word)工具详解使用说明
    一键自动生成 java junit 测试代码神器 gen-test-plugin 入门介绍
    基于 asm 实现比 spring BeanUtils 性能更好的属性拷贝框架
    java 反射借助 asm 获取参数名称最优雅简单的方式
    xml-mapping xml 与 java 对象转换映射框架,像 XStream 一样优雅地读写xml
    从零开始手写 spring ioc 框架,深入学习 spring 源码
    java property 配置文件管理工具框架,避免写入 property 乱序
    从零开始手写 dubbo rpc 框架
    java bean 属性验证框架 valid
    vue安装及测试mockjs
  • 原文地址:https://www.cnblogs.com/jing-an-feng-shao/p/9074925.html
Copyright © 2020-2023  润新知