算法描述:
先取一个小于n的整数d1作为第一个步长,把文件的全部记录分成d1个组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个步长d2<d1重复上述的分组和排序,直至所取的步长dt=1(dt<dt-l<…<d2<d1),即所有记录放在同一组中进行直接插入排序为止。
该方法实质上是一种分组插入方法。
步长的选择是希尔排序的重要部分。只要最终步长为1任何步长序列都可以工作。算法最开始以一定的步长进行排序。然后会继续以一定步长进行排序,最终算法以步长为1进行排序。当步长为1时,算法变为插入排序,这就保证了数据一定会被排序。
Donald Shell 最初建议步长选择为并且对步长取半直到步长达到 1,但还有其他的步长可以达到更好的效果
算法度量:
数据结构 数组
最差时间复杂度 根据步长序列的不同而不同。 已知最好的: O(n\log^2 n)
最优时间复杂度 O(n)
平均时间复杂度 根据步长序列的不同而不同。
最差空间复杂度 O(n)
最佳算法 非最佳算法
源码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
void print_ary( int * ary, unsigned int len )
{
while( len-- > 0 ) {
printf("%d ", *ary++ );
}
putchar('\n');
}
void create_rondom_number(int **parray, unsigned int number)
{
struct timeval tpstart;
unsigned int i =0;
if (NULL != *parray)
{
return;
}
*parray = (int *)malloc(sizeof(unsigned int) * number);
(void)memset(*parray, 0, sizeof(unsigned int) * number);
gettimeofday(&tpstart,NULL);
//srandom(time(NULL));
srandom(tpstart.tv_usec);
for (i=0; i<number; ++i)
{
//(*parray)[i] = random()%number; // range is [0, number-1]
//(*parray)[i] = random()%(b-a) + a; //range is [a, b)
((*parray)[i] = 1 + (int) ((double)number * rand() / (RAND_MAX + 1.0))); // [1, number]
}
}
void shell_sort(int a[], int n)
{
int gap = 0;
int i, j, temp;
while (gap<=n)
{
gap = gap * 3 + 1;
}
printf("gap=%d\n", gap);
while (gap > 0)
{
/*对gap列数同时进行插入排序,因为插入排序开始假定第一个数是已经排好的,
* 要从第二个数开始与前边的数进行比较。同理对gap列数同时进行插入排序时,
* 也认为第一列的数是已经排完序的,要从第二列开始与前边的数进行比较,
* 第二列数即地gap个元素, 注意:不是排完第一列再排第二列,而是同时排,
* 即不是排完0,gap,2gap,3gap...,再排1,gap+1,2gap+2,3gap+3...
* 而是从gap,gap+1,gap+3至n挨个列交替的进行排序 */
for ( i = gap; i < n; i++ )
{
temp = a[i];//将a[i]列的即将插入到前边的数暂存到temp中
a[i] = 10000;//调试代码
j = i - gap;//与a[i]这一列数的前一个元素开始比较
printf("\n\ntemp=a[%d]=%d, j=%d gap=%d: ", i, temp, j, gap); print_ary(a, n);
/*依次与a[i]列的前边每个数进行比较*/
while (( j >= 0 ) && ( a[j] > temp ))
{
printf("a[%d]=%d move back to a[%d], a[%d] is idle: ", j, a[j], j+gap, j);
/* a[i]列的前一个元素比temp大,则要将此数往后移一个位置 */
a[j + gap] = a[j]; //将比temp大的往后移
a[j] = 10000;//调试代码
j = j - gap;
print_ary(a, n);
printf("--next element j=%d\n", j);
}
a[j + gap] = temp; //插入到比temp小的数的后边
printf("temp=%d insert to a[%d]: ", temp, j+gap); print_ary(a, n);
}
gap = ( gap - 1 ) / 3;
}
}
int main( int argc, char ** argv )
{
int *pary = NULL;
if (argc !=2)
{
printf("\nUsage: %s Number\n", argv[0]);
return -1;
}
create_rondom_number(&pary, (unsigned int)atoi(argv[1]));
printf("\n\nrandom number: ");
print_ary( pary, (unsigned int)atoi(argv[1]) );
printf("Start sortting: \n");
shell_sort( pary, (unsigned int)atoi(argv[1]));
printf("\n\nafter sorted: ");
print_ary( pary, (unsigned int)atoi(argv[1]) );
return 0;
}
运行结果:
[root@localhost sort]# ./shell 10
random number: 10 2 1 4 10 4 1 4 10 7
Start sortting:
gap=13
temp=a[4]=10, j=0 gap=4: 10 2 1 4 10000 4 1 4 10 7
temp=10 insert to a[4]: 10 2 1 4 10 4 1 4 10 7
temp=a[5]=4, j=1 gap=4: 10 2 1 4 10 10000 1 4 10 7
temp=4 insert to a[5]: 10 2 1 4 10 4 1 4 10 7
temp=a[6]=1, j=2 gap=4: 10 2 1 4 10 4 10000 4 10 7
temp=1 insert to a[6]: 10 2 1 4 10 4 1 4 10 7
temp=a[7]=4, j=3 gap=4: 10 2 1 4 10 4 1 10000 10 7
temp=4 insert to a[7]: 10 2 1 4 10 4 1 4 10 7
temp=a[8]=10, j=4 gap=4: 10 2 1 4 10 4 1 4 10000 7
temp=10 insert to a[8]: 10 2 1 4 10 4 1 4 10 7
temp=a[9]=7, j=5 gap=4: 10 2 1 4 10 4 1 4 10 10000
temp=7 insert to a[9]: 10 2 1 4 10 4 1 4 10 7
temp=a[1]=2, j=0 gap=1: 10 10000 1 4 10 4 1 4 10 7
a[0]=10 move back to a[1], a[0] is idle: 10000 10 1 4 10 4 1 4 10 7
--next element j=-1
temp=2 insert to a[0]: 2 10 1 4 10 4 1 4 10 7
temp=a[2]=1, j=1 gap=1: 2 10 10000 4 10 4 1 4 10 7
a[1]=10 move back to a[2], a[1] is idle: 2 10000 10 4 10 4 1 4 10 7
--next element j=0
a[0]=2 move back to a[1], a[0] is idle: 10000 2 10 4 10 4 1 4 10 7
--next element j=-1
temp=1 insert to a[0]: 1 2 10 4 10 4 1 4 10 7
temp=a[3]=4, j=2 gap=1: 1 2 10 10000 10 4 1 4 10 7
a[2]=10 move back to a[3], a[2] is idle: 1 2 10000 10 10 4 1 4 10 7
--next element j=1
temp=4 insert to a[2]: 1 2 4 10 10 4 1 4 10 7
temp=a[4]=10, j=3 gap=1: 1 2 4 10 10000 4 1 4 10 7
temp=10 insert to a[4]: 1 2 4 10 10 4 1 4 10 7
temp=a[5]=4, j=4 gap=1: 1 2 4 10 10 10000 1 4 10 7
a[4]=10 move back to a[5], a[4] is idle: 1 2 4 10 10000 10 1 4 10 7
--next element j=3
a[3]=10 move back to a[4], a[3] is idle: 1 2 4 10000 10 10 1 4 10 7
--next element j=2
temp=4 insert to a[3]: 1 2 4 4 10 10 1 4 10 7
temp=a[6]=1, j=5 gap=1: 1 2 4 4 10 10 10000 4 10 7
a[5]=10 move back to a[6], a[5] is idle: 1 2 4 4 10 10000 10 4 10 7
--next element j=4
a[4]=10 move back to a[5], a[4] is idle: 1 2 4 4 10000 10 10 4 10 7
--next element j=3
a[3]=4 move back to a[4], a[3] is idle: 1 2 4 10000 4 10 10 4 10 7
--next element j=2
a[2]=4 move back to a[3], a[2] is idle: 1 2 10000 4 4 10 10 4 10 7
--next element j=1
a[1]=2 move back to a[2], a[1] is idle: 1 10000 2 4 4 10 10 4 10 7
--next element j=0
temp=1 insert to a[1]: 1 1 2 4 4 10 10 4 10 7
temp=a[7]=4, j=6 gap=1: 1 1 2 4 4 10 10 10000 10 7
a[6]=10 move back to a[7], a[6] is idle: 1 1 2 4 4 10 10000 10 10 7
--next element j=5
a[5]=10 move back to a[6], a[5] is idle: 1 1 2 4 4 10000 10 10 10 7
--next element j=4
temp=4 insert to a[5]: 1 1 2 4 4 4 10 10 10 7
temp=a[8]=10, j=7 gap=1: 1 1 2 4 4 4 10 10 10000 7
temp=10 insert to a[8]: 1 1 2 4 4 4 10 10 10 7
temp=a[9]=7, j=8 gap=1: 1 1 2 4 4 4 10 10 10 10000
a[8]=10 move back to a[9], a[8] is idle: 1 1 2 4 4 4 10 10 10000 10
--next element j=7
a[7]=10 move back to a[8], a[7] is idle: 1 1 2 4 4 4 10 10000 10 10
--next element j=6
a[6]=10 move back to a[7], a[6] is idle: 1 1 2 4 4 4 10000 10 10 10
--next element j=5
temp=7 insert to a[6]: 1 1 2 4 4 4 7 10 10 10
after sorted: 1 1 2 4 4 4 7 10 10 10
[root@localhost sort]#
参考:
http://zh.wikipedia.org/wiki/%E5%B8%8C%E5%B0%94%E6%8E%92%E5%BA%8F
http://baike.baidu.com/view/178698.htm