希尔排序(第十章 P271 算法10.4,10.5)

希尔排序

 

概述:

希尔排序是插入排序的一种,又称“缩小增量排序”。是直接插入排序算法的一种更高效的改进版本。

希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。

 

排序过程:

 

  • 如下图,为需要排序的初始关键字。
  • 首先把较大的数据集合分割成若干个小组(逻辑上分组),然后对每一个小组分别进行插入排序,此时,插入排序所作用的数据量比较小(每一个小组),插入的效率比较高。   这里我们把该序列分出五个子序列。     可以看出,是按下标相隔距离为5分的组,也就是说把下标相差5的分到一组,比如这个例子中a[0]与a[5]是一组、a[1]与a[6]是一组...,这里的差值(距离)被称为增量 。                                                                                                                             

 

  • 第一趟排序,每个分组进行插入排序后,各个分组就变成了有序的了(整体不一定有序)。此时,整个数组变的部分有序了(有序程度可能不是很高)                                                                     
  • 第二趟排序,增量为3 。                                                                                                                                                           
  • 最后设置增量为1,则整个数组被分为一组,此时,整个数组已经接近有序了,插入排序效率高。

 

 

 

算法性能:

 

稳定性:由于多次插入排序,我们知道一次插入排序是稳定的,不会改变相同元素的相对顺序,但在不同的插入排序过程中,相同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱,所以希尔排序是不稳定的。

希尔排序的时间是所取 “增量” 序列的函数,这涉及一些数学上尚未解决的难题。以下列举几个增量序列了解一下:

1.   {1,2,4,8,...}这种序列并不是很好的增量序列,使用这个增量序列的时间复杂度(最坏情形)是O(n^2)

2.    Hibbard提出了另一个增量序列{1,3,7,...,2^k-1},这种序列的时间复杂度(最坏情形)为O(n^1.5)

3.    Sedgewick提出了几种增量序列,其最坏情形运行时间为O(n^1.3),其中最好的一个序列是{1,5,19,41,109,...}

 

 

 

代码:

 

#include<stdio.h>
typedef int InfoType; /* 定义其它数据项的类型 */


 /* 对两个数值型关键字的比较约定为如下的宏定义 */
#define EQ(a,b) ((a)==(b))
#define LT(a,b) ((a)<(b))
#define LQ(a,b) ((a)<=(b))


/* -------------------------------     待排记录的数据类型   --------------------------------*/


#define MAXSIZE 20 /* 一个用作示例的小顺序表的最大长度 */
typedef int KeyType; /* 定义关键字类型为整型 */
typedef struct
{
	KeyType key; /* 关键字项 */
	InfoType otherinfo; /* 其它数据项,具体类型在主程中定义 */
}RedType; /* 记录类型 */

typedef struct
{
	RedType r[MAXSIZE + 1]; /* r[0]闲置或用作哨兵单元 */
	int length; /* 顺序表长度 */
}SqList; /* 顺序表类型 */

/* ------------------------------------------------------------------------------------------*/




/* -------------------------------    希尔排序    -----------------------------------*/


void ShellInsert(SqList *L, int dk)
{ /* 对顺序表L作一趟希尔插入排序。本算法是和一趟直接插入排序相比, */
  /* 作了以下修改: */
  /* 1.前后记录位置的增量是dk,而不是1; */
  /* 2.r[0]只是暂存单元,不是哨兵。当j<=0时,插入位置已找到。算法10.4 */
	int i, j;
	for (i = dk + 1; i <= (*L).length; ++i)
		if LT((*L).r[i].key, (*L).r[i - dk].key)
		{ /* 需将(*L).r[i]插入有序增量子表 */
			(*L).r[0] = (*L).r[i]; /* 暂存在(*L).r[0] */
			for (j = i - dk; j > 0 && LT((*L).r[0].key, (*L).r[j].key); j -= dk)
				(*L).r[j + dk] = (*L).r[j]; /* 记录后移,查找插入位置 */
			(*L).r[j + dk] = (*L).r[0]; /* 插入 */
		}
}

void print(SqList L)
{
	int i;
	for (i = 1; i <= L.length; i++)
		printf("%d ", L.r[i].key);
	printf("\n");
}

void print1(SqList L)
{
	int i;
	for (i = 1; i <= L.length; i++)
		printf("(%d,%d)", L.r[i].key, L.r[i].otherinfo);
	printf("\n");
}

void ShellSort(SqList *L, int dlta[], int t)
{ /* 按增量序列dlta[0..t-1]对顺序表L作希尔排序。算法10.5 */
	int k;
	for (k = 0; k < t; ++k)
	{
		ShellInsert(L, dlta[k]); /* 一趟增量为dlta[k]的插入排序 */
		printf("第%d趟排序结果: ", k + 1);
		print(*L);
	}
}


/* ------------------------------------------------------------------------------------------*/


 /* 检验以上操作的主程序 */


#define N 10
#define T 3
void main()
{
	RedType d[N] = { {49,1},{38,2},{65,3},{97,4},{76,5},{13,6},{27,7},{49,8},{55,9},{4,10} };
	SqList l;
	int i, dt[T] = { 5,3,1 }; /* 增量序列数组 */
	for (i = 0; i < N; i++)
		l.r[i + 1] = d[i];
	l.length = N;
	printf("排序前: ");
	print(l);
	ShellSort(&l, dt, T);
	printf("排序后: ");
	print1(l);
}

运行结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值