希尔排序 插入排序的升级

直接插入排序我们是知道的,它比冒泡和选择快的原因是数据交换的次数相对较少,不像冒泡那样,每次内循环遍历时两个两个数比较然后换来换去,如果是完全反序的,那就得每次都进行交换操作,交换操作可比逻辑判断操作要费时多,这也是之前问的,为什么时间复杂度明明差不多,但运行时间却天差地别,冒泡排序排10万个数据的时候居然用了1分多种。
然而要减少交换操作,那就需要序列向有序化靠拢,这样实际的交换数据操作减少很多,时间也会大幅减少。
如何使数列偏于有序化呢。这里有个很重要的思想,那就是分段。
我们可以让一个长序列,分为好多段或组,给它们分别进行排序,那就变得基本有序了。
何为基本有序?
用升序来说,就是前面的数据普遍偏小,后面的数据普遍偏大.
比如一个长为10的数据。
 1 9 3  4 5 6  6 1 8
这不是基本有序,看似 除了 9 和1     剩下的1 3 4 56 6 8挺有序的,但9在很前面,1在很后面,这不能算基本有序
再比如一个长为10的数据
3 21   6 5  4  6  9   87 
你一看,我天,什么321 ,654 6,987这全反过来了,乱的一匹,但这勉强算基本有序,因为前三位数也基本是最小的三个,中间4位位数也是不大不小的四个,最后3个也是最大的三个数。
所以该如何分组使得数列基本有序呢?
比如9个数。
能让前三个一排序?中间三个一排序?后面三个一排序吗?
显然是不能的!!

应该使前面三个普遍小于中间三个,让中间三个普遍小于后面三个。
那么这种分组方式就出来了:
让9个数中的 1   4   7号位置排序  2 5 8号位置排序   3,6,9号位置排序。

希尔排序就使用的是这个思想。

首先设置一个dka表示一组元素的多少隔。
使dka慢慢增大。
最后dka增长为数列长度时,其实就只有一组了,那就变成了直接插入排序了。此时的数列已经基本有序了,所以执行的时间会大大减少。

反过来我们也可以直接设置有多少组,使组数慢慢减少为1,也是相同的道理。
比如我设置一个表示组数多少的数组dka[];
那10个数举例
我设置dka[]为{5,3,1}
5组就代表从第6个数开始,第6个数和第1个数排序,第7个和第二个数排序。。。。。第10个和第5个数排序
3组....
代码如下


由于1万个数据对于希尔来说太快了,所以这次使用了10万个数据测试结果

这是dka为{5,3,1}的情况,只用了1.5秒

如果把分组细化,效率也会更快
下面是dka为{50,20,10,5,3,1}




dka为{300,150,100,50,20,10,5,3,1};


之前说的几种排序,冒泡。选择。插入的平均时间复杂度都在0(n^2)的级别

希尔的时间复杂度却达到了蜕变  O(n^1.3)


至于稳定性。我们知道直接插入是稳定的,可能会猜测进化版不会不稳定吧。
结果还真是不稳定,因为有了分组,而且每组的每个数据都相距甚远(dka长) 所以插入数据的时候有非常频繁的跳跃式插入,这样肯定就是不稳定的了,至于如何改进为稳定的,我之前的博客有写过一个方法,有兴趣,可以去看看。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章