基本算法之希尔排序

希尔排序是在1995年希尔教授(shell)提出来的,它是对插入排序算法的一种优化,同时也是属于不稳定排序中的一种。

基本思想如下:

第一步:需要在一连串毫无顺序的数字排列中取一个增量increment,把相隔increment的数字划分出来成为一个个子序列,把每个子序列用插入排序的排好序列,由于此时increment比较高,子序列中元素较少。

第二步:缩小增量,再以increment为间隔划分子序列,再把每个子序列用插入进行排序,由于increment变小了,所以子序列中药排序的元素就变多了。

第三步:不断缩小增量increment、划分、排序,直到increment = 1进行最后一个排序,此时整个序列中,大部分已经排序完毕,因此最后一次排序基本不用什么对换操作了。

假如此时有一个随机序列 {69,56,12,136,3,55,46,99,98,25},现在就用希尔排序来完成有小到大的排列。

第一步,确定增量increment,这个可以由序列元素的个数num来决定,increment = num / 2 = 5,再以5这个增量为间隔进行子序列划分,也就是说,从第0个元素开始,间隔为5的就可以划分成同一个子序列。

此时的子序列中就有{69,55} 、 {56,46}、 {12,99}、 {136,98}、 {3,25};

接下来就需要用插入排序法将每一个子序列进行排序,按照由小到大调整各自的所在的位置;

第一步排序后的序列,如下图:

第二步,缩小增量,按照shell教授的建议,increment = increment / 2向下取整,当然这并不是最优的取法,不同的增量选取会让希尔排序产生不一样的效率,这里我们姑且选用increment = increment/2 = 2,然后划分子序列。

此时的子序列中就有{55,12,3,56,136}和{46,98,69,99,25};

接下来就需要用插入排序法将每一个子序列进行排序,按照由小到大调整各自的所在的位置;

第二步排序后的序列,如下图:

到了这里会发现,这时候的序列有了一个从小到大的形,大部分元素已经是排好了。

第三步,increment = increment / 2 = 1,此时的子序列就是一整个序列,只要按照直接插入法排序便可,由于之前的两步已经做好了大部分的排序工作,这时候排序的工作量就会少之又少,只需要稍微移动几个元素的位置就可以了,这个就是希尔排序的优势所在。

 

以下是C语言代码实现过程:

void Into_Sort(int array[],int num)
{
	int i=1,j=i-1,temp;
	if(array[i] < array[j])      //先判断第一和第二个元素的大小关系
	{
		temp = array[i];
		array[i] = array[j];
		array[j] = temp;
	}
	for(i=2;i<num;i++)			//从第三个元素开始
	{
		j = i-1;
		while(j>=0)
		{
			if(array[i] < array[j] && array[i] > array[j-1])
			{
				temp = array[i];
				for(int k=i-1;k>=j;k--)
				{
					array[k+1] = array[k];  //将元素们往后移一位
				}
				array[j] = temp;
				break;
			}
			j--;
		}
	}
}

我在主函数中,让其随机产生1000个随机数,通过希尔排序来进行排序

#include "Shell_Sort.h"

int main()
{
	int num;
	int shell[1000] = {0};
	srand((unsigned)time(NULL));
	//产生1000个元素的随机数组
	for(num=0;num<10000;num++)
	{
		shell[num] = rand()%1000;
	}
	Shell_Sort(shell,1000);
	printf("希尔排序后的结果是:\n");
	for(num=0;num<1000;num++)
	{
		printf("%d ",shell[num]);
	}
	
	return 0;
}

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值