天天看点

(二)希尔排序法一、简介二、步骤三、示例四、代码实现五、评价六、参考资料

一、简介

希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。

希尔排序是基于插入排序的以下两点性质而提出改进方法的: 1、插入排序在对几乎已经排好序的数据操作时,效率高, 即可以达到线性排序的效率 2、对于大规模乱序数组插入排序很慢,因为它只会交换相邻的元素,因此元素只能一点一点地从数组的一端移动到另一端。

希尔排序简单地改进了插入排序,交换不相邻的元素以对数组的局部进行排序,并最终用插入排序将局部有序的数组排序。(先将整个大数组基本有序,再对大数组来一次插入排序)

思想:使数组中任意间隔为h的元素都是有序的。这样的数组被称为h有序数组。在进行排序时,如果h很大,我们就能将元素移动到很远的地方,为实现更小的h有序创造方便。

二、步骤

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

三、示例

假设有这样一组数[ 13 14 94 33 82 25 59 94 65 23 45 27 73 25 39 10 ],如果我们以步长为5开始进行排序,我们可以通过将这列表放在有5列的表中来更好地描述算法,这样他们就应该看起来是这样:

13 14 94 33 82
25 59 94 65 23
45 27 73 25 39
10
复制代码
           

然后我们对每列进行排序:

10 14 73 25 23
13 27 94 33 39
25 59 94 65 82
45
复制代码
           

将上述四行数字,依序接在一起时我们得到: [ 10 14 73 25 23 13 27 94 33 39 25 59 94 65 82 45 ] 这时10已经移至正确位置了,然后再以3为步长进行排序:

10 14 73
25 23 13
27 94 33
39 25 59
94 65 82
45
复制代码
           

排序之后变为:

10 14 13
25 23 33
27 25 59
39 65 73
45 94 82
94
复制代码
           

最后以1步长进行排序(此时就是简单的插入排序了)。

四、代码实现

template<typename T> //可以使用整数或浮点数作为元素,如果使用类(class)作为元素则需要重载大于(>)运算符。
void sort(T arr[], int len) {
	int gap, i, j;
	T temp;
	for (gap = len >> ; gap > ; gap >>= )	// gap为当时增量
		/* 同时做gap个序列排序 */
		for (i = gap; i < len; i++) {			
			temp = arr[i];		// 保存待插入记录Ri
                        int j = ; //有序区中待比较元素的下标,初始时,从有序区中最后一个元素开始比较起
			/* 按间隔gap寻找插入点 */ 
			for (j = i - gap; j >=  && arr[j] > temp; j -= gap)	// 对步长为 gap 的元素组进行排序
				arr[j + gap] = arr[j];	// 大记录后移
			arr[j + gap] = temp;	// 插入记录Ri
		}
}

int main()
{
	int a[] = { ,,,,,,,,, };
	sort(a,);
	for (int i = ; i < ; i++) {
		cout << a[i] << " ";
	}
}
复制代码
           

五、评价

稳定性:不稳定。我们知道一次插入排序是稳定的,但在不同的插入排序过程中,相同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱,即希尔排序中相等数据可能会交换位置。

时间性能:希尔排序的平均时间复杂度为O(nlog2n)

适用范围:中等大小规模表现良好,对规模非常大的数据排序不是最优选择。不适用于链式结构

六、参考资料

排序:直接插入+希尔排序 希尔排序 排序:插入排序之希尔排序(缩小增量排序)

白话经典算法系列之三 希尔排序的实现 中国MOOC大学-程序设计基础-6.问题解决和算法基础3