简简单单学算法-排序算法一(希尔排序)

本文详细介绍了希尔排序的思想及其实现过程,并通过实例演示了排序步骤。同时,对比了希尔排序与传统插入排序的时间效率,分析了希尔排序的时间复杂度及稳定性。

一.希尔排序思想

希尔排序也是一种插入排序方法,实际上是一种分组插入方法。先取定一个小于n的整数d1作为第一个增量,把表的全部记录分成d1个组,所有距离为d1的倍数的记录放在同一个组中,在各组内进行直接插入排序;然后,取第二个增量d2(<d1),重复上述的分组和排序,直至所取的增量dt=1(dt<dt-1<…<d2<d1),即所有记录放在同一组中进行直接插入排序为止。    

     例如:将 n 个记录分成 d 个子序列: 
       { R[0],   R[d],     R[2d],…,     R[kd] } 
       { R[1],   R[1+d], R[1+2d],…,R[1+kd] } 
         … 
       { R[d-1],R[2d-1],R[3d-1],…,R[(k+1)d-1] }

这个是排序过程每次按增量分为一组,在组内排好序;理论说多了有点晕,来点实际例子:  

例如:

数据未排序:[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]

1.取增量d为排序个数一半:10/2=5

距离为5的数据分为一组,共5组[10,5],[9,4],[8,3],[7,2],[6,1] 
分组排序[5,10],[4,9],[3,8],[2,7],[1,6],将分组数据复原到数组中
d=5:[5, 4, 3, 2, 1, 10, 9, 8, 7, 6]

2.增量递减一半:5/2=2

距离为2的数据分为一组,共2组[5,3,1,9,7],[4,2,10,8,6]
排序为[1,3,5,7,9] [2,4,6,8,10],将分组数据复原到数组中
d=2:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]


3.增量递减一半:2/2=1

d=1:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]


直到增量递减到1为止,增量大小视情况而定,分组排序时用的是插入算法,当然也可以选用适用排序算法。

我认为希尔排序是对插入排序的一种优化。

二、时间复杂度。  

最好情况:由于希尔排序的好坏和步长d的选择有很多关系,因此,目前还没有得出最好的步长如何选择(现在有些比较好的选择了,但不确定是否是最好的)。所以,不知道最好的情况下的算法时间复杂度。  
最坏情况下:O(N*logN),最坏的情况下和平均情况下差不多。  
平均情况下:O(N*logN)

三、稳定性。  

由于多次插入排序,我们知道一次插入排序是稳定的,不会改变相同元素的相对顺序,但在不同的插入排序过程中,相同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱,所以shell排序是不稳定的。(有个猜测,方便记忆:一般来说,若存在不相邻元素间交换,则很可能是不稳定的排序。)


四、与插入算法对比

经过随机数据多次测试结果如下:
插入算法:1万个随机整数排序平均耗时0.1s
希尔算法:1万个随机整数排序平均耗时0.025s

插入算法:10万个随机整数排序平均耗时7.9s
希尔算法:10万个随机整数排序平均耗时0.06s
可能每次产生的随机数存在不确定性,但平均耗时可以看出希尔算法优势明显;

五、源码


	public void sort (int array[],int n)
	{
		int i=0,j=0,temp=0;
		int d=n/2;   /*初始增量*/
		
		while (d>0){
			for (i=d;i<n;i++){
				//分组排序,距离是d的为一组
				for(j=i-d;j>=0 && array[j] > array[j+d];j=j-d){
					temp=array[j];
					array[j]=array[j+d];
					array[j+d]=temp;
				}
			}
			//System.out.println("d="+d+Arrays.toString(array));
			d=d/2; /*增量递减*/
		}
	}	


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值