文字描述
希尔排序又称缩小增量排序,也属于插入排序类,但在时间效率上较之前的插入排序有较大的改进。
从之前的直接插入排序的分析得知,时间复杂度为n*n, 有如下两个特点:
(1)如果待排序记录本身就是“正序”时, 其时间复杂度可减少为n。
(2)当待排序记录数很小时,直接插入排序的效率也比较高;
希尔排序正是从这两点分析出发对直接插入排序进行了改进。它的基本思想是:先将整个待排记录序列分割成为若干个子序列分别进行直接插入排序,待整个序列中的记录“基本有序“时,再对全体记录进行一次直接插入排序。
示意图
算法分析
希尔排序的空间复杂度是所取增量数组的个数加1。
希尔排序的时间复杂度分析是一个复杂的问题,因为它的时间是所取”增量”序列的函数,这涉及一些数学上尚未解决的难题。但是在大量的前人做的实验基础上推出:当n在某个特定范围内,希尔排序所需的比较和移动次数均约为n^(1.3), 当n无穷大时,可减少到n(log2n)^2。
增量序列可以有各种取法,但是需注意:应使增量序列中的值没有除1之外的公因子,并且最后一个增量值必须等于1。
希尔排序是不稳定的
代码实现
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 #define DEBUG 5 6 #define EQ(a, b) ((a) == (b)) 7 #define LT(a, b) ((a) < (b)) 8 #define LQ(a, b) ((a) <= (b)) 9 10 #define MAXSIZE 20 11 typedef int KeyType; 12 typedef int InfoType; 13 typedef struct{ 14 KeyType key; 15 InfoType otherinfo; 16 }RedType; 17 18 typedef struct{ 19 RedType r[MAXSIZE+1]; 20 int length; 21 }SqList; 22 23 //依次打印顺序表L中的下标和关键字 24 void PrintList(SqList L){ 25 int i = 0; 26 printf("下标值:"); 27 for(i=0; i<=L.length; i++){ 28 printf("[%d] ", i); 29 } 30 printf(" 关键字:"); 31 for(i=0; i<=L.length; i++){ 32 printf(" %-3d", L.r[i].key); 33 } 34 printf(" 其他值:"); 35 for(i=0; i<=L.length; i++){ 36 printf(" %-3c", L.r[i].otherinfo); 37 } 38 printf(" "); 39 return ; 40 } 41 42 /* 43 *对顺序表L作一趟希尔插入排序。本算法和一趟直接插入 44 *排序相比,作了以下修改: 45 * 1。前后记录位置的增量为dk, 而不是1 46 * 2。r[0]只是暂存单元,不是哨兵 47 */ 48 void ShellInsert(SqList *L, int dk) 49 { 50 int i = 0, j = 0; 51 for(i=dk+1; i<=L->length; ++i){ 52 //需将L->r[i]插入有序增量子表 53 if(LT(L->r[i].key, L->r[i-dk].key)){ 54 //暂存在L->r[0] 55 L->r[0] = L->r[i]; 56 for(j=i-dk; j>0&<(L->r[0].key, L->r[j].key); j-=dk){ 57 //记录后移,找插入位置 58 L->r[j+dk] = L->r[j]; 59 } 60 //插入位置找到,插入数据 61 L->r[j+dk] = L->r[0]; 62 } 63 } 64 } 65 66 //按照增量序列dlta[0..t-1]对顺序表L作希尔排序 67 void ShellSort(SqList *L, int dlta[], int t) 68 { 69 #ifdef DEBUG 70 printf("输入数组: "); 71 PrintList(*L); 72 #endif 73 int k = 0; 74 for(k=0; k<t; k++){ 75 //一趟增量为dlta[k]的插入排序 76 ShellInsert(L, dlta[k]); 77 #ifdef DEBUG 78 printf("第%d趟增量%d希尔排序后: ", k, dlta[k]); 79 PrintList(*L); 80 #endif 81 } 82 } 83 84 int main(int argc, char *argv[]) 85 { 86 if(argc < 2){ 87 return -1; 88 } 89 SqList L; 90 int i = 0; 91 for(i=1; i<argc; i++){ 92 if(i>MAXSIZE) 93 break; 94 L.r[i].key = atoi(argv[i]); 95 L.r[i].otherinfo = 'a'+i-1; 96 } 97 L.length = (i-1); 98 L.r[0].key = 0; 99 L.r[0].otherinfo = '0'; 100 //希尔排序的增量 依次取9 5 3 1 101 int dlta[4] = {9,5,3,1}; 102 //调用希尔排序算法 103 ShellSort(&L, dlta, 4); 104 return 0; 105 }
运行