算法--希尔排序

希尔排序

它的实质是分组插入排序,又称缩小增量排序,它是基于插入排序的思想

直接插入排序对于基本有序的数组,且基数N较小的情况下性能最好,希尔排序就是利用直接插入排序的这个特点,将较大的数组拆分为较小的子序列进行。

思想

先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。因为直接插入排序在元素基本有序的情况下(接近最好情况),效率是很高的,因此希尔排序在时间效率上比单纯的直接插入排序有较大提高。
图形描述:
我们以以n=10的一个数组 {49, 38, 65, 97, 26, 13, 27, 49, 55, 7}为例来走一下希尔排序的过程:

在这里插入图片描述

首先 gap = 10 / 2 = 5,整个数组被分成 5 组,分组后的子数组分别是:{49,13},{38,27},{65,49},{97,55},{26,7},子数组进行直接插入排序后为: {13,49},{27,38},{49,65},{55,97},{7,26}。

在这里插入图片描述

此时 gap = 5 / 2 = 2,整个数组被分成 2 组,分组后的子数组是:{13,49,7,38,97},{27,55,49,65,26},子数组进行直接插入排序后为:{7,13,38,49,97},{26,27,49,55,65}。

在这里插入图片描述

现在 gap = 2 / 2 = 1,所以直接对整个数组进行直接插入排序,至此整个希尔排序完成。

void ShellSort(int a[],int n)
{
	int gap,j;
	for (gap = n / 2; gap > 0; gap /= 2)  //控制步长
	for (j = gap; j < n;++j)  //++j操作是很巧妙地,这步操作省去了对数组进行分组的一层循环
	{
		int tmp = a[j];
		int prev = j - gap;
 
		while (prev>=0 && a[j]<a[prev]){  //这里是直接插入排序的核心步骤
			a[j] = a[prev];
		    prev -= gap;
		    }
 
		a[prev + gap] = tmp;
	}
}

时间复杂度和空间复杂度:

时间复杂度:希尔排序的时间复杂度较其他排序没有那么直观,一般认为它的时间复杂度为,比直接插入要好。 希尔排序对于中等规模(N <= 1000)的序列具有较高的效率。

空间复杂度:O(1)

稳定性:

是不稳定的,在排序过程中,相同关键字的领先关系有可能会发生变化。

例如,有待排序序列为{2,4,1,2},设 gap = 2, 排序后的结果为{1,2,2,4}。

增量的取法:

最初希尔提出 gap = N / 2,再取 gap = gap / 2,直到 gap = 1 为止,这种方案的缺点是,奇数位置的元素在最后一步才会与偶数位置的元素进行比较,使得希尔排序效率降低。因此后来 knuth 提出 gap = N / 3 +1 的方案,没有给出证明。已知的最好步长序列是由Sedgewick提出的(1, 5, 19, 41, 109,…),该序列来自个算式。关于这点说到这里了。。。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值