排序算法之希尔排序

一.希尔排序基本原理

    希尔排序又称缩小增量排序,因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

第二次 gap = 5 / 2 = 2,一共有2个小组每组5个元素
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);
}
      同样,抽象封装排序函数,最后和前面类似把希尔排序用测试模块测试一遍。


你可能感兴趣的:(排序,算法,希尔排序,C语言)