算法—希尔排序

概念

希尔排序(Shell’s Sort)是插入排序的一种又称“缩小增量排序”(Diminishing Increment Sort),是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因D.L.Shell于1959年提出而得名。
希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。 **——[摘自百度百科] **

它出现的原因是,插入排序由于效率太低O(n2),而它的效率是在当时第一批打破O(n2)的算法O(n^1.25),因为插入排序擅长处理长度较短的, 部分有序(或有序)的数组,所以希尔排序在插入排序之前,先将数列排来差不多,相对整齐之后,在最后一次插入排序的时候效率就相对高一些,避免了无差别的插入排序无脑对比相邻俩元素的情况发生。

温馨提示:看这篇之前最好先搞懂插入排序:https://blog.csdn.net/user11223344abc/article/details/81567579

理解

看了这个图,我也只有个大概的感性认知,简单的说,它就是根据数组长度计算出的一个变量h为步长,分h趟进行的插入排序。它的复杂度是随着h来定的,那么这个h该如何取值呢?目前最优解是h = 3 * h + 1,h初始值为1,取最接近数组长度的h值作为初始步长,而后,再进行递减。
PS:由于h值与希尔排序的复杂度是息息相关的,所以它取值的最优解,这个问题是个数学问题,目前我是跟随业界标准的。

分析

比如这样一个数组:

int a[] = { 500,86,1,77,55,24,9 };

  • 1.它的长度是7
  • 2.带入h值目前最优解公式:h = 3 * h + 1,得出结果:h = 1,4,13 …
  • 3.由于4最接近长度7,所以取4为h初始值
  • 4.开始进行比较,那么我们画个图来揭示本例的比较流程

  • 5.那么我们推导一下这个h在排序过程中如何进行递减,因为 h 是 {1 , 4 , 13 , 40 …},40/3 = 13(int自己舍位),13/3=4(int自己舍位),4/3=1(int自己舍位)。所以我们可以将来递减的公式推导为 h = h/3。

那么代码该如何来写呢?

1.h步长处理


	//希尔排序
	int * shellSort(int *a, int len) {
	
		int h = 1;
	
		//计算出步长的值
		while (h < len)
		{
			h = 3 * h + 1; 
		}
		h = h / 3;
	
		//进行希尔排序....
		while (h >= 1)
		{
	
			//TODO 排序逻辑...
	
			h = h / 3; //递减
		}
		
		return a;
	}

2.排序逻辑的编写

排序逻辑,总的来说,这个希尔排序相当于是当h值不为1时,一趟趟的只交换位置,当h为1时,进行普通的插入排序(插入排序我沿用了之前写的方法)。

另外,我这么写显得比较笨拙,但逻辑上相对简单,实际上还可以再进行优化,比如把h=1和h!=1的逻辑融合在一起,但实际上本质都一样,只不过多了常数级的代码,并没有什么大的影响,后续我会将优化版本更新上来,目前就先到这个程度。


	//进行希尔排序....
		while (h >= 1)
		{
	
			if (h == 1) {
				printArray(a, "最后一次插入排序之前:", len);
				insertionSort(a,len);
			}
			else
			{
				for (int i = 0; i + h < len ; i++)
				{
					if (a[i] > a[i + h]) {
						int temp = a[i];
						a[i] = a[i + h];
						a[i + h] = temp;
					}
				}
			}
	
			h = h / 3; //递减
		}

Demo

运行结果:

希尔排序前
500,86,1,77,55,24,9,
最后一次插入排序之前
55,24,1,77,500,86,9,
希尔排序后
1,9,24,55,77,86,500,
请按任意键继续. . .

具体代码我不贴出来了,这里给出在线地址:
https://github.com/zj614android/algorithm/blob/master/Insertion_sort/Insertion_sort/ShellSort.cpp

Thanks

https://blog.csdn.net/ltyqljhwcm/article/details/53369718
https://www.imooc.com/article/21707
https://blog.csdn.net/jianfpeng241241/article/details/51707618
http://liuwangshu.cn/algorithm/2-insert-hill.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值