思路:首先选取一个增量d(类似等差数列的公差),一般先设为array.Length/2,将数组中距离为d的数据分到同一个组中,由此分为多个组,在每组进行直接插入排序;然后d递减,再分为多个组,再在每组进行直接插入排序,直到d=1。希尔排序相对于插入排序的优点在于:每次比较的数的距离更大,比较之后移动的距离更大,减少了复制的次数,而且由于最后d=1,此时相当于对整个数组进行插入排序,所以排序结果一定是正确的。
时间复杂度:O(nlog2n) ~O(n^2)。
代码如下:
static void Main(string[] args)
{
int[] array = { 1, 5, 3, 6, 10, 55, 9, 2, 87, 12, 34, 75, 33, 47, 99, 35, 19 };
ShellSortM(array);
foreach(int item in array)
{
Console.Write("{0} ", item);
}
Console.ReadKey();
}
/// <summary>
/// 希尔排序
/// </summary>
/// <param name="array"></param>
private static void ShellSort(int[] array)
{
int d = array.Length;
int len = array.Length; //数组长度
//增量希尔排序
for(d/=2;d>0;)
{
if (d % 2 == 0) d++; //确保最后d=1
//按d分组
for(int i=0;i<d;i++)
{
//每组执行直接插入排序
for(int j=i+d;j<len;j+=d)
{
//当后面的数比前面的数小时进行排序
if(array[j]<array[j-d])
{
int temp = array[j]; //持有更小的数
int k = 0;
//比temp大的数后移
for(k=j-d;k>=i && temp<array[k];k-=d)
{
array[k + d] = array[k];
}
//插入到比它小的数的后面
array[k + d] = temp;
}
}
}
//减小增量
d = d / 2;
}
}
总结:希尔排序的思想较插入排序抽象得多,代码也更难写出来,需要仔细想想才能理解。