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

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 的概念,增加了冒泡排序的算法效率。

原文地址:https://www.cnblogs.com/jing-an-feng-shao/p/9074925.html

时间: 2024-10-10 20:16:42

排序算法杂谈(一) —— 量化数组的有序程度的相关文章

排序算法杂谈(五) —— 关于快速排序的优化策略分析

1. 前提 排序算法(六) -- 归并排序 排序算法(七) -- 快速排序 排序算法杂谈(四) -- 快速排序的非递归实现 2. 优化策略1:主元(Pivot)的选取 归并排序(Merge Sort)有一个很大的优势,就是每一次的递归都能够将数组平均二分,从而大大减少了总递归的次数. 而快速排序(Quick Sort)在这一点上就做的很不好. 快速排序是通过选择一个主元,将整个数组划分(Partition)成两个部分,小于等于主元 and 大于等于主元. 这个过程对于数组的划分完全就是随机的,俗

排序算法杂谈(二) —— 冒泡排序的递归实现

众所周知,循环和递归,在很多情况下是可以互相转换的. 那么,冒泡排序(Bubble Sort),作为典型的双重循环结构,也可以将其转化成递归形式. 但是,将递归转化为循环,对于程序的运行是有益的,因为它避免了不可预知的"方法压栈"的现象出现. 而将循环化为递归,多数情况下,不推荐这么做,即使递归的代码可能实现地非常漂亮.漂亮与高效往往是冲突的. 所以,以下的冒泡排序仅作参考,读者可以用它来拓宽思维.但是,永远不要这样写冒泡排序! public final class BubbleSor

C语言 选择排序算法原理和实现 从数组中 找出最小的元素然后交换位置

#include <stdio.h> int main(void) { /* 选择排序算法 原理:从数组中 找出最小的元素然后交换位置: */ int a[10] = {9,5,10,7,2,3,1,6,8,4}; int i=0,j=0; int n = sizeof(a)/4; //外循环n-1轮 for(i=0;i<n-1;i++){ int pos = i;//始终指向最小的位置 for(j=i+1;j<n;j++){ if(a[j]<a[pos]){ pos = j

【整理】常见排序算法及其时间复杂度总结

原文出处: 1. 白话经典算法系列之八 MoreWindows白话经典算法之七大排序总结篇 2. 面试常用算法总结--排序算法(java版) 3. 常见排序算法小结 本篇主要整理了冒泡排序,直接插入排序,直接选择排序,希尔排序,归并排序,快速排序,堆排序七种常见算法,是从上面三篇博文中摘抄整理的,非原创. 一.冒泡排序 主要思路是: 通过交换相邻的两个数变成小数在前大数在后,这样每次遍历后,最大的数就"沉"到最后面了.重复N次即可以使数组有序. 冒泡排序改进1: 在某次遍历中,如果没有

经典排序算法的PHP实现类

近期广受笔试摧残,对于各种排序也是晕头转向. 更坑爹的是貌似大多都是用C++.Java实现相关算法,让我搞PHP的情何以堪,更何况,PHP本身就有排序函数sort(),其实来说,是很简单的,这也可能是为什么不用PHP进行排序吧. 但考虑到PHP毕竟也是一门面向对象的语言吧,我们利用原生的语法,也是可以实现经典排序算法的,先不说性能如何,切不要妄自菲薄吧. 下面为具体的经典排序算法的PHP实现类. <?php /** * Author: helen * CreateTime: 2016/4/15

若干排序算法简单汇总(二)

转载请注明出处 http://blog.csdn.net/pony_maggie/article/details/36706131 作者:小马 一希尔排序 上一篇讲到的直接插入排序,时间复杂度O(n^2). 请在脑海里想一下它的过程.如果一个序列本来就是有序的,对它排序的时间复杂度是O(n).所以当序列基本有序时,插入排序排序的效率大大提高,因为减少了移动的动作. 另外,直接插入排序还有一个特点,当n比较小时,它的效率比较高. 希尔排序正是基于上面两个思想做的一种改进算法.它先将整个序列分成若干

数据结构——排序算法总结

排序(Sorting)就是将一组对象依照规定的次序又一次排列的过程,排序往往是为检索而服务的.它是数据处理中一种非常重要也非经常常使用的运算.比如我们日常学习中的查字典或者书籍的文件夹.这些都事先为我们排好序,因此大大减少了我们的检索时间,提高工作效率. 排序可分为两大类: 内部排序(Internal Sorting):待排序的记录所有存放在计算机内存中进行的排序过程: 外部排序(External Sorting):待排序的记录数量非常大,内存不能存储所有记录.须要对外存进行訪问的排序过程. 外

几个排序算法的python实现

几个排序算法 几个排序算法 冒泡排序 选择排序 插入排序 快速排序 quick sort 冒泡排序 冒泡排序是比较简单的排序方法,它的思路是重复的走过要排序的序列,一次比较两个元素,如果顺序错误,就交换元素的位置,直到没有元素需要交换位置. 原 始 6 1 8 5 9 7 第一次 1 6 8 5 9 7 第二次 1 6 8 5 9 7 第三次 1 6 5 8 9 7 第四次 1 6 5 8 9 7 第五次 1 6 5 8 7 9 …… 第N次 1 5 6 7 8 9 代码实现: 1.lst =

选择排序算法(排序详解)

直接插入排序(Selection Sort)算法 1.基本思想: 选择排序(Selection sort)是一种简单直观的排序算法.它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完. 选择排序是不稳定的排序方法(比如序列[5, 5, 3]第一次就将第一个[5]与[3]交换,导致第一个5挪动到第二个5后面). n个记录的文件的直接选择排序可经过n-1趟直接选择排序得到有序结果: ①初始状态:无序区为R[1..n],有序区为空.