经典排序之希尔排序

希尔排序(Shell Sort):将待排序数据分组,各组之内进行插入排序。
缩小增量(间隔)排序
在开始希尔排序以前我们要先知道插入排序的适用场合:待排序数据元素个数相对较少或待排序数据中的元素现所在位置与排序完成以后的位置相差不远。
假如待排序数据为:12、28、3、9、13、1、7、22、24、16、5。
我们传统思想上的分组可能就是挨着的元素在一起,我们3个分一组,12、28、 3;9、13、1;7、22、24;16、5;在对每一组进行插入排序之后,结果只是这组内的元素顺序有序,比如第一组的结果为3、12、28;可是对于我们要排序的所有数据来说,大的元素可能还是在前面,小的元素可能还是在后面,所以我们采用传统思想上的分组不合适,我们采用隔几个元素的方法来分组,假如数据中的12、1、5;一组,三个数排序后变成1、5,12,小的数据就被我们送到了相对前边,大的元素就会被送到相对后面。按照间隔分组,那么间隔是怎样确定的呢?为了教学方便,我们用二分确定间隔,但在实际的生产生活中用的并不是二分,可是对于希尔排序的思想是不变的。
第一轮:这组数据一共11个元素,n/2=5,隔五个元素一组。对于12、1、5;第一组,保存1,1跟12比,1比12小,12向后移动,数据变成,12,12,5;再向前,没有元素了,数据变成1,12,5;保存5,5跟12比,5比12小,12向后移动,数据变成,1,12,12,5跟1比,5比1大,5放在1后面,1,5,12;这样第一组元素就排好序了。第二组,保存7,7比28小,28向后移动,数据变成28,28,再向前没有元素,7放在第一个,数据变成7,28,第三组,3,22,保存22,22比3大,不改变。第四组 … … 直到最后一组结束。数据变成1、7、3、9、13、5、28、22、24、16、12。
在这里插入图片描述

第二轮:接下来的间隔发生改变为n/2/2=2;第一组,1、3、13、28、24、12;保存3,3跟1比,3比1大,不动,保存13,13跟3比,比3大,不动,保存28,28跟13比,28比13大,不动,保存24,24跟28比,24比28小,28向后移动,数据变成1、3、13、28、28、12;24跟13比,24比13大,放在13后面,数据变成1、3、13、24、28、12;保存12,12跟28比,12比28小,28向后移动,数据变成1、3、13、24、28、28;12跟24比,12比24小,24向后移动,数据变成1、3、13、24、24、28;12跟13比,12比13小,13向后移动,数据变成1、3、13、13、24、28;12跟3比,12比3大,12放在3的后面,数据变成1、3、12、13、24、28;第二组结束后数据变成1、5、3、7、12、9、13、16、24、22、28;
在这里插入图片描述

第三轮:间隔变成n/2/2/2=1;间隔是5的时候,分成5组,进行插入排序,间隔是2,分成两组进行插入排序,现在间隔是1,对这组数据直接进行插入排序也完全没有问题,因为经过我们前几轮的操作过后,我们发现待排序数据中的元素已经越来越向着它应该去的位置移动了,也就是说符合插入排序所适用场合,可以直接进行插入排序。

代码如下:

void ShellSort(int arr[] ,int nLength)
{
    
    
	if(arr == NULL || nLength <= 0) return;

	int nGap;
	int j;
	int i;
	int k;
	int temp;

	//间隔
	for(nGap=nLength/2;nGap >=1;nGap/=2)
	{
    
    
		//组
		for(i = 0;i < nGap;i++)
		{
    
    
			//插入排序
			for(j=i+nGap;j<nLength;j+=nGap)
			{
    
    
				k = j-nGap; //有序的最后一个元素
				temp = arr[j];
				while(arr[k]>temp && k>=i)
				{
    
    
					arr[k+nGap] = arr[k];
					k-=nGap;
				}
				arr[k+nGap] = temp;
			}
		}
	}
}

猜你喜欢

转载自blog.csdn.net/scarificed/article/details/113445994