一.希尔排序基本原理
希尔排序又称缩小增量排序,因DL.Shell于1959年提出而得名。希尔排序的基本思想是:先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。
以长度为10的一个数组 9, 3, 5, 7, 6, 1, 2, 4, 8, 10为例:
第一次 gap = 10 / 2 = 5,一共有5个小组每组2个元素
9, 3, 5,7,6, 1, 2, 4, 8,10
A1 B1 C1 D1 E1 A2 B2 C2 D2 E2
A1/A2.。。。E1/E2分别是一组。
第一次排序后:
1,2,4,7,6,9,3,5,8,10
1,2,4,7,6,9,3,5,8,10
数组下标0,2,4,6,8是一组。1,3,5,7,9是另外一组。
第二次排序后:
1,2,3,5,4,9,6,10,8
第三次 gap = 2 / 2 = 1最后一次快速排序得到:
1,2,3,4,5,6,7,8,9,10
希尔排序核心代码:
void shellsort(int a[], int n)
{
int i, j, gap;
for (gap = n / 2; gap > 0; gap /= 2)
for (i = 0; i < gap; i++)
{
for (j = i + gap; j < n; j += gap)
if (a[j] < a[j - gap])
{
int temp = a[j];
int k = j - gap;
while (k >= 0 && a[k] > temp)
{
a[k + gap] = a[k];
k -= gap;
}
a[k + gap] = temp;
}
}
}
二.算法改进
希尔排序是直接插入排序的变形,把序列分为若干个子序列,分别插入排序。我们可以把gap/=2>0看成需要插入排序的次数。和直接插入排序不同的地方在于,这里相邻元素的步长为gap,而不是1。当gap为1的时候,希尔排序和直接插入排序是一致的。我们可以得到如下代码:
int shell_sort(void** ppvArray, size_t length, DataCompare compare)
{
int gap = 0;
int nIndex = 0;
if(ppvArray == NULL || compare == NULL)
{
return (-1);
}
if(length < 2)
{
return (0);
}
for(gap = length/2; gap > 0; gap/=2)
{
for(nIndex = gap; nIndex < length; nIndex++)
{
if(compare(ppvArray[nIndex], ppvArray[nIndex - gap]) < 0)
{
void* temp = ppvArray[nIndex];
int nInset = nIndex - gap;
for(;nInset >= 0 && compare(ppvArray[nInset], temp) > 0; )
{
ppvArray[nInset + gap] = ppvArray[nInset];
nInset-=gap;
}
ppvArray[nInset + gap] = temp;
}
}
}
return (0);
}
同样,抽象封装排序函数,最后和前面类似把希尔排序用测试模块测试一遍。