基本思想
先将整个待排序列分割成若干个子序列,这些子序列分别进行插入排序,待整个序列中的记录“基本有序”时,再对全体序列进行依次插入排序。
希尔排序的特点:
- 不断缩小间隔增量
- 多遍插入排序
算法过程
以待排序列{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)的两个元素相对顺序不会发生改变 - 算法适用范围:希尔排序的时间效率还是比较不错的,对于中等大小的数组它的运行时间是可以接受的。如果你需要解决一个排序问题而又没有系统排序函数可用(例如直接接触硬件或是运行于嵌入式系统中的代码),可以先用希尔排序,然后再考虑是否值得将它替换为更加复杂的排序算法。