希尔排序

希尔排序的基本思想:选定第一个增量d1(一般取d1=n/2),从第一条记录起,把全部记录按此值进行分组,所有相距为d1的记录为一组,然后在各组中进行直接插入排序,然后缩小间隔(一般采用希尔提出的取法:di+1 = di/2 ),使用新的间距重复上述分组和排序过程;如此反复,直到增量d=1,即所有数字在同一组内排序。


如对记录数n=8的序列进行希尔排序(同颜色为一组,每组进行希尔排序):

(1)d1=n/2 = 8/2 = 4 共分成4组:    60   71  49  11  82  49  3  66   

(2)d2=d1/2 = 4/2 = 2 共分成2组:    60   49  3   11  82  71  49   66

(3)d3=d2/2 = 2/2 = 1 共分成1组: 3  11  49  49  60  66  82  71


算法思路(通过三层循环来实现 ):

(1)外循环以各种不同的间距距离d进行排序,直到d=1;

(2)第二重循环是在某一个d值下对各组进行排序,若在某个d值下发生记录的交换,则须继续第三重循环,直至各组内均无记录的交换为止,即各组内已经完成了排序任务。

(3)第三重循环从第一个记录开始,以某个d值为间距进行组内比较,若有逆序,进行交换。


以下是严格按照定义来写的代码(t[]为待排序数组,n为数组长度):

 

void xeinsert0(int t[],int n)
{
	int i,j,d,temp;
	for(d=n/2;d>0;d/=2)//增量,取di=n/2,di+1=di/2
		for(i=0;i<d;i++)//共分成d组数据,分别进行直接插入排序
		{
			for(j=i+d;j<n;j+=d)//对第i组数据进行插入排序
			{
				if(t[j]<t[j-d])//当待插入元素 < 已排好序列的最后一个元素,则需查找正确位置插入,否则插入到已排好的序列最后(即不需移动)
				{
					temp = t[j];
					j = j-d;
					while(j>=0&&temp<t[j])//查找正确插入的位置
					{
						t[j+d] = t[j];
						j-=d;
					}
					t[j+d] = temp;//插入正确的位置
				}
			}
		}
}



上面的代码虽然对直观的理解希尔排序有帮助,但代码量大、不够简洁清晰。因此进行下改进和优化,从数组下标为i(i=d1)开始,作为待插入元素,与i-d1(下标为0)进行比较,若结果为小于,使用直接插入排序进行插入。然后处理下一个元素:i++,数组下标为i的与作为待插入元素,与i-d1(下标为1)进行比较,以此类推,一直到i=n为止。代码如下:

void xeinsert(int t[],int n)
{
	int i,j,d,temp;
	for(d=n/2;d>0;d/=2)//增量
	{
		for(i=d;i<n;i++)//插入排序
		{
			if(t[i]<t[i-d]){
				temp = t[i];
				j = i-d;
				while(j>=0&&t[j]>temp)
				{
					t[j+d] = t[j];
					j-=d;
				}
				t[j+d] = temp;
			}
		}
	}
}


测试函数:

//打印数组
void myPrint(int t[],int n)
{
	for(int i=0;i<n;i++)
	{
		printf("%d\t",t[i]);
	}
	printf("\n");
}

void main()
{
	int t[] = {60,71,49,11,82,49,3,66};
	xeinsert(t,8);
	myPrint(t,8);
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值