希尔排序 Shell Sort,也称递减增量排序算法



希尔排序,也称递减增量排序算法,是插入排序的一种高速而稳定的改进版本。

希尔排序是基于插入排序的以下两点性质而提出改进方法的:

  • 插入排序在对几乎已经排好序的数据操作时, 效率高, 即可以达到线性排序的效率
  • 但插入排序一般来说是低效的, 因为插入排序每次只能将数据移动一位

希尔排序
Step-by-step visualisation of Shellsort
Shellsort with gaps 23, 10, 4, 1 in action.
分类 排序算法
数据结构 数组
最差时间复杂度 根据步长串行的不同而不同。 已知最好的: O(n\log^2 n)
最优时间复杂度 O(n)
平均时间复杂度 根据步长串行的不同而不同。
最差空间复杂度 O(n)
最佳算法 非最佳算法

void shellsort (int[] a, int n)
 {
     int i, j, k, temp, gap;
     int[] gaps = { 1,5,13,43,113,297,815,1989,4711,11969,27901,84801,
                    213331,543749,1355339,3501671,8810089,21521774,
                    58548857,157840433,410151271,1131376761,2147483647 };
     for (k=0; gaps[k]<n; k++) ;
     while (--k >= 0)
     {
         gap = gaps[k];
         for (i=gap; i<n; i++)
         {
             temp = a[i];
             j = i;
             while (j>=gap && a[j-gap]>temp)
             {
                 a[j] = a[j-gap];
                 j = j-gap;
             }
             a[j] = temp;
         }
     }
 }

common 

int j, p, gap;
comparable tmp;


for (gap = N/2; gap > 0; gap = gap/2)

  for ( p = gap; p < N ; p++)
  {
     tmp = a[p];
     for (j = p; j >= gap && tmp < a[j- gap]; j = j - gap)
     
          a[j] = a[j-gap];

     a[j] = tmp;
  }

}


步长串行

步长的选择是希尔排序的重要部分。只要最终步长为1任何步长串行都可以工作。算法最开始以一定的步长进行排序。然后会继续以一定步长进行排序,最终算法以步长为1进行排序。当步长为1时,算法变为插入排序,这就保证了数据一定会被排序。

Donald Shell 最初建议步长选择为\frac{n}{2}并且对步长取半直到步长达到 1。虽然这样取可以比\mathcal{O}(n^2)类的算法(插入排序)更好,但这样仍然有减少平均时间和最差时间的余地。 可能希尔排序最重要的地方在于当用较小步长排序后,以前用的较大步长仍然是有序的。比如,如果一个数列以步长5进行了排序然后再以步长3进行排序,那么该数列不仅是以步长3有序,而且是以步长5有序。如果不是这样,那么算法在迭代过程中会打乱以前的顺序,那就不会以如此短的时间完成排序了。

步长串行 最坏情况下复杂度
{n/2^i} \mathcal{O}(n^2)
2^k - 1 \mathcal{O}(n^{3/2})
2^i 3^j \mathcal{O}( n\log^2 n )

已知的最好步长串行是由Sedgewick提出的 (1, 5, 19, 41, 109,...),该串行的项来自 9 * 4^i - 9 * 2^i + 1 和 4^i - 3 * 2^i + 1 这两个算式[1].这项研究也表明“比较在希尔排序中是最主要的操作,而不是交换。”用这样步长串行的希尔排序比插入排序堆排序都要快,甚至在小数组中比快速排序还快,但是在涉及大量数据时希尔排序还是比快速排序慢

另一个在大数组中表现优异的步长串行是(斐波那契数列除去0和1将剩余的数以黄金分区比的两倍的进行运算得到的数列):(1, 9, 34, 182, 836, 4025, 19001, 90358, 428481, 2034035, 9651787, 45806244, 217378076, 1031612713, …)[2]


Increment sequences
What should the increment sequence be?
There are many choices for the increment sequence. Any sequence that begins at 1 and always increases will do, although some yield better performance than others:


Shell's original sequence: N/2 , N/4 , ..., 1 (repeatedly divide by 2);
Hibbard's increments: 1, 3, 7, ..., 2k - 1 ;
Knuth's increments: 1, 4, 13, ..., (3k - 1) / 2 ;
Sedgewick's increments: 1, 5, 19, 41, 109, ....
It is obtained by interleaving the elements of two sequences:
1, 19, 109, 505, 2161,….., 9(4k – 2k) + 1, k = 0, 1, 2, 3,…
5, 41, 209, 929, 3905,…..2k+2 (2k+2 – 3 ) + 1, k = 0, 1, 2, 3, …


Analysis
A Shellsort's worst-case performance using Hibbard's increments is Θ(n 3/2).
The average performance is thought to be about O(n5/4)

The exact complexity of this algorithm is still being debated.

Experience shows that for mid-sized data (tens of thousands elements) the algorithm performs nearly as well if not better than the faster n log n sorts.

Detailed analysis:
http://www.iti.fh-flensburg.de/lang/algorithmen/sortieren/shell/shellen.htm
希尔排序,也称 递减增量排序算法,是 插入排序的一种高速而稳定的改进版本。

希尔排序是基于插入排序的以下两点性质而提出改进方法的:

  • 插入排序在对几乎已经排好序的数据操作时, 效率高, 即可以达到线性排序的效率
  • 但插入排序一般来说是低效的, 因为插入排序每次只能将数据移动一位

希尔排序
Step-by-step visualisation of Shellsort
Shellsort with gaps 23, 10, 4, 1 in action.
分类 排序算法
数据结构 数组
最差时间复杂度 根据步长串行的不同而不同。 已知最好的: O(n\log^2 n)
最优时间复杂度 O(n)
平均时间复杂度 根据步长串行的不同而不同。
最差空间复杂度 O(n)
最佳算法 非最佳算法

void shellsort (int[] a, int n)
 {
     int i, j, k, temp, gap;
     int[] gaps = { 1,5,13,43,113,297,815,1989,4711,11969,27901,84801,
                    213331,543749,1355339,3501671,8810089,21521774,
                    58548857,157840433,410151271,1131376761,2147483647 };
     for (k=0; gaps[k]<n; k++) ;
     while (--k >= 0)
     {
         gap = gaps[k];
         for (i=gap; i<n; i++)
         {
             temp = a[i];
             j = i;
             while (j>=gap && a[j-gap]>temp)
             {
                 a[j] = a[j-gap];
                 j = j-gap;
             }
             a[j] = temp;
         }
     }
 }

common 

int j, p, gap;
comparable tmp;


for (gap = N/2; gap > 0; gap = gap/2)

  for ( p = gap; p < N ; p++)
  {
     tmp = a[p];
     for (j = p; j >= gap && tmp < a[j- gap]; j = j - gap)
     
          a[j] = a[j-gap];

     a[j] = tmp;
  }

}


步长串行

步长的选择是希尔排序的重要部分。只要最终步长为1任何步长串行都可以工作。算法最开始以一定的步长进行排序。然后会继续以一定步长进行排序,最终算法以步长为1进行排序。当步长为1时,算法变为插入排序,这就保证了数据一定会被排序。

Donald Shell 最初建议步长选择为\frac{n}{2}并且对步长取半直到步长达到 1。虽然这样取可以比\mathcal{O}(n^2)类的算法(插入排序)更好,但这样仍然有减少平均时间和最差时间的余地。 可能希尔排序最重要的地方在于当用较小步长排序后,以前用的较大步长仍然是有序的。比如,如果一个数列以步长5进行了排序然后再以步长3进行排序,那么该数列不仅是以步长3有序,而且是以步长5有序。如果不是这样,那么算法在迭代过程中会打乱以前的顺序,那就不会以如此短的时间完成排序了。

步长串行 最坏情况下复杂度
{n/2^i} \mathcal{O}(n^2)
2^k - 1 \mathcal{O}(n^{3/2})
2^i 3^j \mathcal{O}( n\log^2 n )

已知的最好步长串行是由Sedgewick提出的 (1, 5, 19, 41, 109,...),该串行的项来自 9 * 4^i - 9 * 2^i + 1 和 4^i - 3 * 2^i + 1 这两个算式[1].这项研究也表明“比较在希尔排序中是最主要的操作,而不是交换。”用这样步长串行的希尔排序比插入排序堆排序都要快,甚至在小数组中比快速排序还快,但是在涉及大量数据时希尔排序还是比快速排序慢

另一个在大数组中表现优异的步长串行是(斐波那契数列除去0和1将剩余的数以黄金分区比的两倍的进行运算得到的数列):(1, 9, 34, 182, 836, 4025, 19001, 90358, 428481, 2034035, 9651787, 45806244, 217378076, 1031612713, …)[2]


Increment sequences
What should the increment sequence be?
There are many choices for the increment sequence. Any sequence that begins at 1 and always increases will do, although some yield better performance than others:


Shell's original sequence: N/2 , N/4 , ..., 1 (repeatedly divide by 2);
Hibbard's increments: 1, 3, 7, ..., 2k - 1 ;
Knuth's increments: 1, 4, 13, ..., (3k - 1) / 2 ;
Sedgewick's increments: 1, 5, 19, 41, 109, ....
It is obtained by interleaving the elements of two sequences:
1, 19, 109, 505, 2161,….., 9(4k – 2k) + 1, k = 0, 1, 2, 3,…
5, 41, 209, 929, 3905,…..2k+2 (2k+2 – 3 ) + 1, k = 0, 1, 2, 3, …


Analysis
A Shellsort's worst-case performance using Hibbard's increments is Θ(n 3/2).
The average performance is thought to be about O(n5/4)

The exact complexity of this algorithm is still being debated.

Experience shows that for mid-sized data (tens of thousands elements) the algorithm performs nearly as well if not better than the faster n log n sorts.

Detailed analysis:
http://www.iti.fh-flensburg.de/lang/algorithmen/sortieren/shell/shellen.htm
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值