经典排序算法(二)希尔排序

基本思想

先将整个待排序列分割成若干个子序列,这些子序列分别进行插入排序,待整个序列中的记录“基本有序”时,再对全体序列进行依次插入排序。

希尔排序的特点:

  • 不断缩小间隔增量
  • 多遍插入排序

算法过程

以待排序列{81,94,11,96,12,35,17,95,28,58,41,75,15}为例。
在这里插入图片描述

首先,我们取间隔增量为5,将序列分为多个子序列,并分别对其进行插入排序:
在这里插入图片描述
然后,增量减小,再次排序:
在这里插入图片描述
最后,对“基本有序”的序列,再对全体序列进行依次插入排序(也即间隔增量为1)。
在这里插入图片描述

图片来源:数据结构-王卓老师

代码实现

/*
参数1:arr。一维数组的首地址
参数2:flag。确定间隔增量的递减序列数组首地址
参数3:length1。一维数组的元素个数(长度)
参数4:length2。递减数组的元素个数(长度)

flag间隔增量数组的取值是希尔排序的一个难点之一,该数组没有唯一取值方式。
如果待排序序列数量很大(>10000),flag数组的建议值为int flag[] = { 121,40,13,4,1 };
*/
int flag[] = {
    
    5,3,1};
void ShellSort(int* arr, int* flag, int length1, int length2)
{
    
    
	for (int p = 0; p < length2; ++p)
	{
    
    
		int h = flag[p];//间隔
		//接下来是间隔为h的插入排序
		for (int i = h + 1; i <= length1; ++i)
		{
    
    
			arr[0] = arr[i];//哨兵位
			int j = i - h;
			for (; j > 0 && arr[j] > arr[0]; j -= h)
			{
    
    
				arr[j + h] = arr[j];
			}
			arr[j + h] = arr[0];
		}
	}
}

总结

  • 算法时间复杂度:无确定值,猜想为 O ( n 1.25 ) − O ( 1.6 n 1.25 ) O(n^{1.25})-O(1.6n^{1.25}) O(n1.25)O(1.6n1.25)之间。
  • 算法空间复杂度: O ( 1 ) O(1) O(1)
  • 算法是否稳定:不稳定
    算法稳定指的是序列通过算法排序后,比较值相同(key)的两个元素相对顺序不会发生改变
  • 算法适用范围:希尔排序的时间效率还是比较不错的,对于中等大小的数组它的运行时间是可以接受的。如果你需要解决一个排序问题而又没有系统排序函数可用(例如直接接触硬件或是运行于嵌入式系统中的代码),可以先用希尔排序,然后再考虑是否值得将它替换为更加复杂的排序算法。

Guess you like

Origin blog.csdn.net/qq_42518941/article/details/115220946