您的位置:首页 > 运维架构 > Shell

【内部排序】三:希尔排序(Shell Sort)的多种实现(不断优化+源码)

2015-04-20 18:09 579 查看
当我们看代码时,一时不能理解的话。画下草图,用实例来分析下,自己举个例子,跟着代码的执行流程一步步走,回过头来再看就明白了。



希尔排序也是一种插入排序方法,实际上是一种分组插入方法。

一、基本思想:

先取定一个小于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称为增量,它的值在排序过程中从大到小逐渐缩小,直至最后一趟排序减为1。

二、排序算法:

每次从1A到1E,从2A到2E,可以改成从1B开始,先和1A比较,然后取2B与2A比较,再取1C与前面自己组内的数据比较…….。这种每次从数组第gap个元素开始,每个元素与自己组内的数据进行直接插入排序。

//希尔排序
void shell_sort(int a[],int n)
{
	int i,j;
	int gap=n/2;          //增量置初值
	while(gap>0)
	{
		for (i=gap;i<n;i++)		//对相隔gap位置的元素组直接插入排序为一趟希尔排序
		{
			int temp=a[i];
			j=i-gap;
			while(j>=0 && temp<a[j])
			{
				a[j+gap]=a[j];
				j=j-gap;
			}
			a[j+gap]=temp;
		}
		gap=gap/2;	//增量减小
	}
}
另一种写法:
void shell_sort2(int a[], int n)
{
	int j, gap;
	
	for (gap = n / 2; gap > 0; gap /= 2)
		for (j = gap; j < n; j++)//从数组第gap个元素开始
			if (a[j] < a[j - gap])//每个元素与自己组内的数据进行直接插入排序
			{
				int temp = a[j];
				int k = j - gap;
				while (k >= 0 && a[k] > temp)
				{
					a[k + gap] = a[k];
					k -= gap;
				}
				a[k + gap] = temp;
			}
}


再将直接插入排序部分内部排序之一:直接插入排序(Straight
Insertion Sorting)的多种实现用中直接插入排序的第三种方法来改写下:



void shell_sort3(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(n1.3);
空间复杂度:O(1)
稳定性:不稳定。
为什么希尔排序比直接插入排序好?

例如:有10个元素要排序。

直接插入排序 希尔排序

大约时间=102=100 d=5:分为5组,时间约为5*22=20

d=2:分为2组,时间约为2*52=50

d=1:分为1组,几乎有序,时间约为10=80
希尔排序中的有序区不是全局有序,不一定归位。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: