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

希尔排序(Shell Sort)是插入排序的一种。也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。

希尔排序是基于插入排序的以下两点性质而提出改进方法的:
          1:插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率。
      2:但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位。
基本思想:
先取一个小于n的整数d1作为第一个 增量 ,把文件的全部记录分组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行 直接插入排序 ;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量

   
=1(
   
<
   
…<d2<d1),即所有记录放在同一组中进行直接插入排序为止。

该方法实质上是一种分组插入方法
比较相隔较远距离(称为 增量)的数,使得数移动时能跨过多个元素,则进行一次比 [2]   较就可能消除多个元素交换。D.L.shell于1959年在以他名字命名的 排序算法中实现了这一思想。算法先将要排序的一组数按某个 增量d分成若干组,每组中记录的下标相差d.对每组中全部元素进行排序,然后再用一个较小的增量对它进行,在每组中再进行排序。当 增量减到1时,整个要排序的数被分成一组,排序完成。
一般的初次取序列的一半为 增量,以后每次减半,直到增量为1。

优劣:

不需要大量的辅助空间,和归并排序一样容易实现。希尔排序是基于插入排序的一种算法, 在此算法基础之上增加了一个新的特性,提高了效率。希尔排序的时间复杂度与增量序列的选取有关,例如希尔增量时间复杂度为O(n²),而Hibbard增量的希尔排序的时间复杂度为O(
   
),希尔排序时间复杂度的下界是n*log2n。希尔排序没有 快速排序算法快 O(n(logn)),因此中等大小规模表现良好,对规模非常大的 数据排序不是最优选择。但是比O(
   
)复杂度的算法快得多。并且希尔排序非常容易实现,算法代码短而简单。 此外,希尔算法在最坏的情况下和平均情况下执行效率相差不是很多,与此同时快速排序在最坏的情况下执行的效率会非常差。 专家们提倡,几乎任何排序工作在开始时都可以用希尔排序,若在实际使用中证明它不够快,再改成快速排序这样更高级的排序算法. 本质上讲, 希尔排序算法 是直接插入排序算法的一种改进,减少了其复制的次数,速度要快很多。 原因是,当n值很大时 数据项 每一趟排序需要移动的个数很少,但数据项的距离很长。当n值减小时每一趟需要移动的数据增多,此时已经接近于它们排序后的最终位置。 正是这两种情况的结合才使希尔排序效率比 插入排序 高很多。S hell算法的性能与所选取的分组长度序列有很大关系。 只对特定的待排序记录序列,可以准确地估算关键词的比较次数和对象移动次数。想要弄清关键词比较次数和记录移动次数与增量选择之间的关系,并给出完整的数学分析,至今仍然是数学难题。
以上取自:https://baike.baidu.com/item/%E5%B8%8C%E5%B0%94%E6%8E%92%E5%BA%8F/3229428?fr=aladdin


数据结构实验之排序六:希尔排序

Time Limit: 1000MS  Memory Limit: 65536KB
Problem Description

我们已经学习了各种排序方法,知道在不同的情况下要选择不同的排序算法,以期达到最好的排序效率;对于待排序数据来说,若数据基本有序且记录较少时, 直接插入排序的效率是非常好的,希尔排序就是针对一组基本有序的少量数据记录进行排序的高效算法。你的任务是对于给定的数据进行希尔排序,其中增量dk=n/(2^k)(k=1,2,3……)

Input

连续输入多组数据,每组输入数据的第一行给出一个正整数N(N <= 10000),随后连续给出N个整数表示待排序关键字,数字间以空格分隔。

 
Output

输出dk=n/2和dk=1时的结果。

Example Input
10
10 9 8 7 6 5 4 3 2 1
10
-5 9 7 -11 37 -22 99 288 33 66
Example Output
5 4 3 2 1 10 9 8 7 6
1 2 3 4 5 6 7 8 9 10
-22 9 7 -11 37 -5 99 288 33 66
-22 -11 -5 7 9 33 37 66 99 288
代码:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
void shellinsert(int a[],int n,int dk)
{
    int i,j,t;
    for(i = dk;i<=n-1;i++)//从第dk+1个数(下标为dk)额数开始。与同一组的数开始比较,插入。
    {
      if(a[i]<a[i-dk])
      {
          t = a[i];
          for(j=i-dk;j>=0&&t<a[j];j = j-dk)//之前写程序的时候把t写成了a[i],结果不对。找错误的时候总认为a[i]是不变的。后来debug,如果a[i]比后面的值小, 后来赋值的过程,a[i]就变化了。
          {
              a[j+dk] = a[j];
          }
          a[j+dk] = t;
      }
    }
}
void shellsort(int a[],int n,int data[],int m)
{
    int i,j;
    for(i = 1;i<=m;i++)
    {
         shellinsert(a,n,data[i]);//一个一个取增量进行排序
         if(i==1||i==m)
         {
             for(j = 0;j<=n-2;j++)
                printf("%d ",a[j]);
             printf("%d\n",a[n-1]);
         }


    }

}
int main()
{
    int n;
    while(scanf("%d",&n) !=EOF)
    {
        int data[10000];
        int a[10005],i;
        for(i = 0;i<=n-1;i++)
        {
            scanf("%d",&a[i]);
        }
       for(i=1;;i++)//将增量放到data数组中。最小的增量为1,最大的增量为2/n
        {
            data[i]= n/pow(2,i);//指数函数,幂函数用pow函数

            if(data[i]==1)
                break;
        }
        shellsort(a,n,data,i);


    }
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值