数据结构-希尔排序

希尔排序

希尔排序:

希尔排序又称缩小增量排序,它的实质是分组插入排序,因DL.Shell于1959年提出而得名。

直接插入排序法,在待排序序列关键字基本有序且关键字个数 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,i,j;
	for (gap = n / 2; gap > 0; gap /= 2)  //控制步长
		for (i = 0; i < gap; ++i)  //这层循环达到分组的目的
		{
			for (j = i + gap; j < n;j += gap)  //对子数组进行直接插入排序
			{
					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;
			}
		}
}

上面的代码对直观的理解希尔排序的过程是有很大的帮助,但不够简明清晰。在这里我们的改进方法是每次从第 gap 个元素出发,对组内元素进行直接插入排序,并且不是先对相对下标值小的子数组一次性完成直接插入排序,而是每组子数组同步进行。

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;
	}
}

下面这种做法的代码也是非常简洁的,与第二种无本质区别,我个人更推荐第二种代码 ,具体使用哪一个就看个人啦

void ShellSort(int a[], int n)
{
	int i, j, gap;
	for (gap = n / 2; gap > 0; gap /= 2)
	for (i = gap; i < n; i++)
	for (j = i - gap; j >= 0 && a[j] > a[j + gap]; j -= gap)
		Swap(a[j], a[j + gap]);
}

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

时间复杂度:希尔排序的时间复杂度较其他排序没有那么直观,一般认为它的时间复杂度为O(N^{1.5}),比直接插入要好。 希尔排序对于中等规模(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,...),该序列来自个算式。关于这点说到这里了。。。 

 

 

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值