排序算法之希尔排序及其增量序列

希尔排序



其他排序方法:选择排序冒泡排序归并排序快速排序插入排序希尔排序


思想

希尔排序大概就是,选一组递减的整数作为增量序列。最小的增量必须为1:\(D_M>D_{M-1}>...>D_1=1\)

  • 先用第一个增量把数组分为若干个子数组,每个子数组中的元素下标距离等于增量;
  • 然后对每个子数组进行简单插入排序
  • 再使用第二个增量,继续同样的操作,直到增量序列里的增量都使用过一次。
    (增量为1时,其实就是对整个数组进行简单插入排序)

图解

看图更容易理解吧:
(借用一下慕课的浙大数据结构课件。因为课件原本是ppt,而我只有pdf,所以颜色没有上齐,请将就将就emmm)

性能

希尔排序快不快主要取决于我们怎么取增量序列,原始希尔排序的取法就是:\(D_M=\lfloor N/2 \rfloor, D_k=\lfloor D_{k+1}/2 \rfloor\)
此增量序列也成为Shell增量序列
原始希尔排序最坏的时间复杂度为\(O(n^2)\)

代码

# 原始希尔排序
# 增量序列为D(M)=N/2, D(k)=D(k+1)/2 向下取整
def shellSort(arr):
    size = len(arr)
    # 正整数右移一位相当于除以2且向下取整
    step = size >> 1
    while step > 0:
        for i in range(step, size):
            j = i
            tmp = arr[j]
            while j >= step:
                if tmp < arr[j - step]:
                    arr[j] = arr[j - step]
                    j -= step
                else:
                    break
            arr[j] = tmp
        step = step >> 1

优化

希尔排序的优化主要是针对增量序列的优化。
增量序列如果取得不好,效率比直接插入排序还要低,下面举个例子(直接借用课件了):

在这个例子里,前几个增量没有起到任何作用(只起到了拖延时间的作用哈哈)。
所以有人就发现了,如果增量之间不互质的话,那有些情况就不管用了。

于是有些大佬们就整出了下面这些增量序列:Hibbard增量序列Knuth增量序列Sedgewick增量序列等等
下面主要介绍Hibbard增量序列Sedgewick增量序列

Hibbard增量序列

Hibbard增量序列的取法为\(D_k=2^k-1\):{1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191...}
最坏时间复杂度为\(O(N^{3/2})\);平均时间复杂度约为\(O(N^{5/4})\)

先来个Hibbard增量序列的获取代码:

# Hibbard增量序列
# D(i)=2^i?1,i>0
def getHibbardStepArr(n):
    i = 1
    arr = []
    while True:
        tmp = (1 << i) - 1
        if tmp <= n:
            arr.append(tmp)
        else:
            break
        i += 1
    return arr

排序代码稍微修改一下就行:

# 希尔排序(Hibbard增量序列)
def shellSort(arr):
    size = len(arr)
    # 获取Hibbard增量序列
    stepArr = getHibbardStepArr(size)
    # 因为要倒着使用序列里的增量,所以这里用了reversed
    for step in reversed(stepArr):
        for i in range(step, size):
            j = i
            tmp = arr[j]
            while j >= step:
                if tmp < arr[j - step]:
                    arr[j] = arr[j - step]
                    j -= step
                else:
                    break
            arr[j] = tmp

至于为什么要用python内置函数reversed(),而不用其它方法,是因为reversed()返回的是迭代器,占用内存少,效率比较高。
如果先使用stepArr.reverse(),再用range(len(arr))的话,效率会比较低;
而且实测reversed也比range(len(arr) - 1, -1, -1)效率高,故使用reversed();
还有就是先stepArr.sort(reverse=True),再用range(len(arr)),同样效率低。
这几种方法比较的测试代码在这里,有兴趣的朋友可以看看:Python列表倒序输出及其效率

Sedgewick增量序列

Sedgewick增量序列的取法为\(D=9*4^i-9*2^i+1\)或\(4^i-3*2^i+1\):{1, 5, 19, 41, 109, 209, 505, 929, 2161...}
最坏时间复杂度为\(O(N^{4/3})\);平均时间复杂度约为\(O(N^{7/6})\)

Sedgewick增量序列的获取代码:

# Sedgewick增量序列
# D=9*4^i-9*2^i+1 或 4^(i+2)-3*2^(i+2)+1 , i>=0
# 稍微变一下形:D=9*(2^(2i)-2^i)+1 或 2^(2i+4)-3*2^(i+2)+1 , i>=0
def getSedgewickStepArr(n):
    i = 0
    arr = []
    while True:
        tmp = 9 * ((1 << 2 * i) - (1 << i)) + 1
        if tmp <= n:
            arr.append(tmp)
        tmp = (1 << 2 * i + 4) - 3 * (1 << i + 2) + 1
        if tmp <= n:
            arr.append(tmp)
        else:
            break
        i += 1
    return arr

排序代码稍微修改一下就行:

# 希尔排序(Sedgewick增量序列)
def shellSort(arr):
    size = len(arr)
    # 获取Sedgewick增量序列
    stepArr = getSedgewickStepArr(size)
    for step in reversed(stepArr):
        for i in range(step, size):
            j = i
            tmp = arr[j]
            while j >= step:
                if tmp < arr[j - step]:
                    arr[j] = arr[j - step]
                    j -= step
                else:
                    break
            arr[j] = tmp


其他排序方法:选择排序冒泡排序归并排序快速排序插入排序希尔排序

原文地址:https://www.cnblogs.com/minxiang-luo/p/12392634.html

时间: 2024-10-08 22:16:40

排序算法之希尔排序及其增量序列的相关文章

排序算法之希尔排序

文章转载自http://www.cnblogs.com/chengxiao/ 希尔排序是希尔(Donald Shell)于1959年提出的一种排序算法.希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序,同时该算法是冲破O(n2)的第一批算法之一.本文会以图解的方式详细介绍希尔排序的基本思想及其代码实现. 希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序:随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组

经典排序算法之希尔排序

? 希尔排序是希尔(Donald Shell)于1959年提出的一种排序算法.希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序,同时该算法是冲破O(n2)的第一批算法之一.希尔排序适合数据量中等情况,几十个到几万个. ? 网上看了好久才彻底明白希尔排序是什么,简单的说将就是按照步进对数据进行分组,对每组分别进行插入排序,直到步进是1的时候则全部完成.在此感谢 dreamcatcher-cx的博客 的讲解. function sortShell(arr)

我的Java开发学习之旅------&gt;Java经典排序算法之希尔排序

一.希尔排序(Shell Sort) 希尔排序(Shell Sort)是一种插入排序算法,因D.L.Shell于1959年提出而得名.Shell排序又称作缩小增量排序. 二.希尔排序的基本思想 希尔排序的中心思想就是:将数据进行分组,然后对每一组数据进行排序,在每一组数据都有序之后 ,就可以对所有的分组利用插入排序进行最后一次排序.这样可以显著减少交换的次数,以达到加快排序速度的目的.       希尔排序的中心思想:先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组.所有距离

排序算法系列——希尔排序

希尔排序同之前介绍的直接插入排序一起属于插入排序的一种.希尔排序算法是按其设计者希尔(Donald Shell)的名字命名,该算法由1959年公布,是插入排序的一种更高效的改进版本.它的作法不是每次一个元素挨一个元素的比较.而是初期选用大跨步(增量较大)间隔比较,使记录跳跃式接近它的排序位置:然后增量缩小:最后增量为 1 ,这样记录移动次数大大减少,提高了排序效率.希尔排序对增量序列的选择没有严格规定. 希尔排序是基于插入排序的以下两点性质而提出改进方法的: 插入排序在对几乎已经排好序的数据操作

算法学习之排序算法:希尔排序

希尔排序又称"缩小增量排序",它的基本思想是:先将整个待排记录序列分割成若干子序列分别进行直接插入排序,待整个序列中的记录"基本有序"时,再对记录进行一次直接插入排序. 希尔排序的一个特点是:子序列的构成不是简单地"逐段分割",而是将相隔某个"增量"的记录组成一个子序列.这就使得希尔排序中关键字较小的记录不是一步一步地往前挪动,而是一次按照"增量"的大小跳跃式地往前移,从而使得在进行最后一趟增量为1的插入排

程序员需要掌握的排序算法之希尔排序(最小增量排序)

希尔排序(最小增量排序) 基本思想:希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序:随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止. package sortalgorithm; public class PublicShellSort { static void shellSort() { int[] sortList = { 1, 3, 2, 4, 10, 7, 8, 9, 5, 6 }; int n = 1,len = s

java排序算法之希尔排序

希尔排序是冲破二次时间屏障的第一批算法之一. 它是通过比较相距一定间隔的元素来工作,各趟比较所用的距离随着算法的进行而减小,直到最后一趟(比较相邻元素)为止.因此希尔排序也叫缩减增量排序. 希尔排序使用一个序列h1,h2,h3...hk来排序. 具体的意思是 第一趟排序比较的是相隔为hk的元素,也就是比较a[i]与a[i+hk],保证a[i]<=a[i+hk]. 第二次比较的是相隔为hk-1的元素,也就是比较a[i]与a[i+hk-1],保证a[i]<=a[i+hk-1]. 直到最后比较的是相

排序算法:希尔排序

希尔排序的实质就是分组插入排序,该方法又称缩小增量排序,因DL.Shell于1959年提出而得名. 该方法的基本思想是:先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序.因为直接插入排序在元素基本有序的情况下(接近最好情况),效率是很高的,因此希尔排序在时间效率上比前两种方法有较大提高. 以n=10的一个数组49, 38, 65, 97, 26,

数据结构排序算法之希尔排序

希尔排序又叫做递减增量排序.在这种排序中,我们将设置一个步长(增量),我们在比较数据时根据增量去进行比较,这样我们的数据会一次性前进很多步,所以希尔排序的效率要比直接插入排序的效率高. 希尔排序的思想就是我们设置一个步长,然后我们根据这个步长进行划分子序列,得到子序列1,子序列2....,然后我们对每个子序列进行直接插入排序,我们也知道当整个数列基本有序的时候使用直接插入排序的效率是非常高的.然后我们缩小步长,则我们划分的子序列的个数越来越少,我们每个子序列中的数据越来越多,则我们基本有序的数据