排序-希尔排序

第一个突破O(n^2)的排序算法。

流程

  1. 选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;
  2. 每次排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,对各个子序列分别进行插入排序。
  3. 进行k次2过程。
  4. 仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。
    由于开始时,t的取值较大,每个子序列中的元素较少,排序速度较快,到排序后期t取值逐渐变小,子序列中元素个数逐渐增多,但由于前面工作的基础,大多数元素已经基本有序,所以排序速度仍然很快。

演示

取t=t/3向下取整+1。

编号a[]操作
0.第一轮9 3 5 4 1 2增量为3,子序列为9 4,进行插入排序。
1.第一轮4 3 5 9 1 2增量为3,子序列为3 1,进行插入排序。
2.第一轮4 1 5 9 3 2增量为3,子序列为5 2,进行插入排序。
3.第二轮4 1 2 9 3 5增量为2,子序列为4 2 3,进行插入排序。
4.第二轮2 1 3 9 4 5增量为2,子序列为1 9 5,进行插入排序。
5.第三轮2 1 3 5 4 9增量为1,子序列为2 1 3 5 4 9,进行插入排序。
6.结束1 2 3 4 5 9

代码

#include <stdio.h>
#define N 100001
int n,a[N];
int main()
{
   scanf("%d",&n);
   for (int i=1;i<=n;++i) scanf("%d",&a[i]);
   for (int t=n/3+1;t!=1;t=t/3+1)
   {
   	for (int i=t+1,j;i<=n;++i)
   	{
   		int x=a[i];
   		for (j=i-t;j>=1;j-=t)
   			if (a[j]>x) a[j+t]=a[j];
   			else break;
   		a[j+t]=x;
   	}
   }
   for (int i=2,j;i<=n;++i)
   {
   	int x=a[i];
   	for (j=i-1;j>=1;--j)
   		if (a[j]>x) a[j+1]=a[j];
   		else break;
   	a[j+1]=x;
   }
   for (int i=1;i<=n;++i) printf("%d ",a[i]);
} 

时间复杂度分析

对希尔排序的时间复杂度分析很困难,在特定情况下可以准确的估算排序码的比较次数和元素移动的次数,但要想弄清楚排序码比较次数和元素移动次数与增量选择之间的依赖关系,并给出完整的数学分析,还没有人能够做到。
增量的取法有各种方案。最初shell提出取t=n/2向下取整,t=t/2向下取整,直到t=1。但由于直到最后一步,在奇数位置的元素才会与偶数位置的元素进行比较,这样使用这个序列的效率会很低。后来Knuth提出取t=n/3向下取整+1。还有人提出都取奇数为好,也有人提出t互质为好。应用不同的序列会使希尔排序算法的性能有很大的差异。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值