前言
希尔排序固然很好,但是某些情况下,有很多缺点。例如下面这种情况:
9 之前的元素都已经有序,只有元素 1 和 2 的位置不对,使用插入排序几乎要移动整个数组的元素,效率很低。
这时候希尔排序横空出世,为的就是应对这种情况,希尔排序(ShellSort)是希尔提出的一种排序算法,它也是插入排序的一种,是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序,也就是它会优先比较距离较远的元素。
希尔排序是把记录按一定的增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的元素越来越多,当增量减至1时,所有元素被分成一组,实际上等同于执行一次上面讲过的插入排序,算法便终止。
从上面这一段话中,你可能不知道什么是增量,增量怎么选取,如何分组。接下来看看具体步骤。(学习希尔排序前最好是已经知道插入排序)
步骤
这是原始的数组,颜色相同的为一组。
初始增量 gap = length / 2 = 5 ,所以我们要分为 5 组,分别是:【8,3】【9,5】【1,4】【7,6】【2,0】
对这 5 组分别进行直接插入排序,如下图,可以看到,较小的元素移动到了前面。然后缩小增量 gap = gap / 2 = 2,那么要分为两组.
对上面两组再分别进行直接插入排序,下图可以看到,此时整个数组的有序程度更近一步啦,再缩小增量 gap = gap / 2 = 1 ,整个数组被分为一组。
经过上面的“调整”,此时再也不像刚开始时:需要大量移动元素。对上面一组进行一趟插入排序,就可得到有序序列,增量再次减小 gap = gap / 2 = 0,此时停止。
这就是整个过程,其中需要对插入排序的过程十分了解才行,接下来直接撸代码。
代码
#include <iostream>
using namespace std;
void ShellSort(int arr[], int left, int right)
{
int gap = (right - left + 1) / 2; //初始增量设为长度的一半
for (; gap > 0; gap = gap /2)
{
for (int i = gap; i <= right; i++) //对每一个数在其分组进行插入排序
{
int current = arr[i];
int j = i - gap;
while (j >= 0 && arr[j] > current)
{
arr[j + gap] = arr[j];
j -= gap;
}
arr[j + gap] = current;
}
}
}
int main(void)
{
int arr[] = { 3,4,5,6,7,8,9,10,1,2 };
int len = sizeof(arr) / sizeof(arr[0]);
ShellSort(arr, 0, len - 1);
for (int i = 0; i < len; i++)
{
cout << arr[i] << " ";
}
return 0;
}
如果上面的代码看不懂,可以结合过程推导