插入排序—希尔排序(Shell`s Sort)

来源:互联网 发布:广电总局网络主播新规 编辑:程序博客网 时间:2024/06/06 03:22

插入排序—希尔排序(Shell`s Sort)


    • 插入排序希尔排序Shells Sort
      • 基本思想
      • 排序流程
      • 算法实现
      • 算法分析

希尔排序(Shell Sort)是插入排序的一种。也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因DL.Shell于1959年提出而得名。

1. 基本思想

先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。

2. 排序流程

  1. 选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;
  2. 按增量序列个数k,对序列进行k 趟排序;
  3. 每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。

这里写图片描述

3. 算法实现

增量序列d = {n/2 ,n/4, n/8 …..1} n为要排序数的个数
说明:先将要排序的一组记录按某个增量d(n/2,n为要排序数的个数)分成若干组子序列,每组中记录的下标相差d。对每组中全部元素进行直接插入排序,然后再用一个较小的增量(d/2)对它进行分组,在每组中再进行直接插入排序。继续不断缩小增量直至为1,最后使用直接插入排序完成排序。

代码

#include <stdio.h>#define N 9int arr[N]={9,1,5,7,6,3,2,8,4};int step=0;int nMove=0; /* 移动次数 */int nFor=0; /* 循环次数 */int nCompare=0; /* 比較次数 */void print(int dk){    int i;    printf("No.%d\tdk=%d\t",step,dk);    for(i=0;i<N;i++)        printf("%d ",arr[i]);    printf("\tnnFor:%2d  Move:%2d  nCompare:%2d\n",nFor,nMove,nCompare);}/* 增量序列t1,t2,…,tk,k趟排序 */void stepSort(int dk){    int i,j,tmp;    step++;    for(i=dk;i<N;i++)    {        nFor++;        if(arr[i]<arr[i-dk])  /* 如果第i个元素大于i-dk元素,直接插入。否则,需要移动有序序列后插入 */        {            tmp=arr[i]; /* 复制为哨兵,存储待排序元素 */            arr[i]=arr[i-dk]; /* 第一次比较后确定需要后移 */            nMove++;            j=i-dk;            while(j>0 && tmp<arr[j-dk]) /* 已经比较了第i-dk个元素,循环从第i-2*dk个开始比较 */            {                nCompare++;                arr[j]=arr[j-dk]; /* 元素后移 */                nMove++;                j-=dk;            }            arr[j]=tmp; /* 在位置j插入第i个元素 */        }        nCompare++;        print(dk);    }}void sort(){    int dk=N/2;    while(dk>0)    {        stepSort(dk);        dk=dk/2;    }}void main(){    printf("Before...\n");    print(0);    printf("Sorting...\n");    sort();    printf("Sorted.\n");}

结果

Before...No.0    dk=0    9 1 5 7 6 3 2 8 4   nnFor: 0  Move: 0  nCompare: 0Sorting...No.1    dk=4    6 1 5 7 9 3 2 8 4   nnFor: 1  Move: 1  nCompare: 1No.1    dk=4    6 1 5 7 9 3 2 8 4   nnFor: 2  Move: 1  nCompare: 2No.1    dk=4    6 1 2 7 9 3 5 8 4   nnFor: 3  Move: 2  nCompare: 3No.1    dk=4    6 1 2 7 9 3 5 8 4   nnFor: 4  Move: 2  nCompare: 4No.1    dk=4    4 1 2 7 6 3 5 8 9   nnFor: 5  Move: 4  nCompare: 6No.2    dk=2    2 1 4 7 6 3 5 8 9   nnFor: 6  Move: 5  nCompare: 7No.2    dk=2    2 1 4 7 6 3 5 8 9   nnFor: 7  Move: 5  nCompare: 8No.2    dk=2    2 1 4 7 6 3 5 8 9   nnFor: 8  Move: 5  nCompare: 9No.2    dk=2    2 1 4 3 6 7 5 8 9   nnFor: 9  Move: 6  nCompare:10No.2    dk=2    2 1 4 3 5 7 6 8 9   nnFor:10  Move: 7  nCompare:11No.2    dk=2    2 1 4 3 5 7 6 8 9   nnFor:11  Move: 7  nCompare:12No.2    dk=2    2 1 4 3 5 7 6 8 9   nnFor:12  Move: 7  nCompare:13No.3    dk=1    1 2 4 3 5 7 6 8 9   nnFor:13  Move: 8  nCompare:14No.3    dk=1    1 2 4 3 5 7 6 8 9   nnFor:14  Move: 8  nCompare:15No.3    dk=1    1 2 3 4 5 7 6 8 9   nnFor:15  Move: 9  nCompare:16No.3    dk=1    1 2 3 4 5 7 6 8 9   nnFor:16  Move: 9  nCompare:17No.3    dk=1    1 2 3 4 5 7 6 8 9   nnFor:17  Move: 9  nCompare:18No.3    dk=1    1 2 3 4 5 6 7 8 9   nnFor:18  Move:10  nCompare:19No.3    dk=1    1 2 3 4 5 6 7 8 9   nnFor:19  Move:10  nCompare:20No.3    dk=1    1 2 3 4 5 6 7 8 9   nnFor:20  Move:10  nCompare:21Sorted.

4. 算法分析

  1. 增量序列的选择
    Shell排序的执行时间依赖于增量序列。好的增量序列的共同特征:
    a. 最后一个增量必须为1;
    b. 应该尽量避免序列中的值(尤其是相邻的值)互为倍数的情况。有人通过大量的实验,给出了较好的结果:当n较大时,比较和移动的次数约在nl.25到1.6n1.25之间。

  2. Shell排序的时间性能优于直接插入排序
    希尔排序在效率上较直接插入排序有较大的改进,希尔排序的时间性能优于直接插入排序的原因:
    a. 当文件初态基本有序时直接插入排序所需的比较和移动次数均较少。
    b. 当n值较小时,nn2的差别也较小,即直接插入排序的最好时间复杂度O(n)和最坏时间复杂度0(n2)差别不大。
    c. 在希尔排序开始时增量较大,分组较多,每组的记录数目少,故各组内直接插入较快,后来增量di逐渐缩小,分组数逐渐减少,而各组的记录数目逐渐增多,但由于已经按di-1作为距离排过序,使文件较接近于有序状态,所以新的一趟排序过程也较快。

  3. 希尔增量:ht=N/2,h[k]=h[k+1]/2,即N/2,(N/2)/2,...,1,其余的增量序列还有Hibbard1,3,...,2k1Sedgewick1,5,19,41,109...该序列中的项或者是94i92i+1或者是4i32i+1。希尔排序的时间复杂度与增量序列的选取有关,例如希尔增量时间复杂度为O(n2),而Hibbard增量的希尔排序的时间复杂度为O(n3/2),希尔排序时间复杂度的下界是nlog2n

  4. 希尔排序是按照不同步长对元素进行插入排序,当刚开始元素很无序的时候,步长最大,所以插入排序的元素个数很少,速度很快;当元素基本有序了,步长很小,插入排序对于有序的序列效率很高。所以,希尔排序的时间复杂度会比O(n2)好一些。希尔排序没有快速排序算法快 O(n(logn)),因此中等大小规模表现良好,对规模非常大的数据排序不是最优选择。但是比O(n2)复杂度的算法快得多。并且希尔排序非常容易实现,算法代码短而简单。 此外,希尔算法在最坏的情况下和平均情况下执行效率相差不是很多。

  5. 希尔排序方法是一个不稳定的排序方法

0 0