希尔(shell)排序算法

希尔(shell)排序是D.L.shell于1959年提出的,它属于插入排序方法,是不稳定的排序方法。 

我们知道,在直接插入排序算法中,每次插入一个数,使有序序列值增加一个节点,并且对插入下一个数没有提供任何帮助。如果比较相隔较远距离(称为增量)的数,是的数移动时能跨过多个元素,则进行一次比较就可以能消除多个元素交换。

1、希尔排序算法的基本思想:

希尔排序算法先将要排序的一组数按某个增量d分为若干组,每组中记录的下标相差d,对每组中全部元素进行排序,然后用一个较小的增量对它进行再次分组,并对每个新租重新进行排序。当增量减到1时,整个要排序的数被分成一组,排序完成。因此希尔排序实质上是一种分组的插入排序方法。

2、希尔排序由于直接插入排序,为什么?

当数组初始状态基本有序时,直接插入排序所需要的比较和移动次数均较少。

当n值较小时,n和n^2的差别也较小,即直接插入排序的最好时间复杂度O(n)和最坏时间复杂度O(n2)差别不大。

在希尔开始时,增量较大,分组较多,每组的记录数目少,故各组内直接插入较快,后来增量d逐渐缩小,分组数逐渐减少,而各组的记录数目逐渐增多。单由于已经按d-1作为距离排过序,数组较接近与有序状态,所以新的一趟排序过程也较快。

因此,希尔排序在效率上较直接插入排序有较大的改进。另外,由于分组的存在,相等元素可能会分在不同组,导致他们的次序可能发生变化,因此希尔排序是不稳定的。

3、思想

希尔排序也是一种插入排序方法,实际上是一种分组插入方法。先取定一个小于n的整数d1作为第一个增量,把表的全部记录分成d1个组,所有距离为d1的倍数的记录放在同一个组中,在各组内进行直接插入排序;然后,取第二个增量d2(<d1),重复上述的分组和排序,直至所取的增量dt=1(dt<dt-1<…<d2<d1),即所有记录放在同一组中进行直接插入排序为止。

例如:将 n 个记录分成 d 个子序列: 

{ R[0],   R[d],     R[2d],…,     R[kd] } 

{ R[1],   R[1+d], R[1+2d],…,R[1+kd] } 

 … 

{ R[d-1],R[2d-1],R[3d-1],…,R[(k+1)d-1] }

说明:d=5 时,先从A[d]开始向前插入,判断A[d-d],然后A[d+1]与A[(d+1)-d]比较,如此类推,这一回合后将原序列分为d个组。<由后向前>

4、时间复杂度

最好情况:由于希尔排序的好坏和步长d的选择有很多关系,因此,目前还没有得出最好的步长如何选择(现在有些比较好的选择了,但不确定是否是最好的)。所以,不知道最好的情况下的算法时间复杂度。

最坏情况下:O(N*logN),最坏的情况下和平均情况下差不多。

平均情况下:O(N*logN)

5、稳定性

由于多次插入排序,我们知道一次插入排序是稳定的,不会改变相同元素的相对顺序,但在不同的插入排序过程中,相同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱,所以shell排序是不稳定的。(有个猜测,方便记忆:一般来说,若存在不相邻元素间交换,则很可能是不稳定的排序。)

6、代码实现

//编程实现希尔插入(Shell)排序
//1、与直接插入排序不同的是:先将数组按大小/2的增量进行分割排序,逐一将增量变小到1为止(h>0),减少插入的次序。
#include<iostream>
using namespace std;

void shell_sort(int a[], int len)
{
	int i,j,h,temp;
	for (h = len / 2; h > 0; h = h / 2)					//控制增量
	{
		//所选的无序区为h增量之后的数据,直到增量数据循环到数组的最后
		for (i = h; i < len; i++)					//这个for循环就是前面的直接插入排序
		{
			temp = a[i];
			for (j = i - h; (j >= 0 && temp < a[j]); j = j - h)	//有序区与无序区相距增量个长度。j为负数,或者无序区数据大于有序区数据就不循环。
			{
				a[j + h] = a[j];
			}
			a[j + h] = temp;
		}
	}
}

static void print_array(int a[], int len)
{
	for (int i = 0; i < len; i++)			//循环打印数组的每个元素
		cout << a[i] << " ";
	cout << endl;
}

void main9mianshiti2()
{
	int a[] = { 7, 3, 5, 8, 9, 1, 2, 4, 6 };
	cout << "before shell sort: ";
	print_array(a, 9);
	shell_sort(a, 9);			//进行shell排序
	cout << "after shell sort: ";
	print_array(a, 9);
	system("pause");
}
7、测试结果

before shell sort:7 3 5 8 9 1 2 4 6

after shell sort:1 2 3 4 5 6 7 8 9


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值