文字描述
和之前的插入排序比,表插入排序可以保证排序过程中不移动记录;因此表插入排序所用的存储结构和之前的顺序存储不同,表插入排序采用静态链表类型作为待排记录序列的存储结构,设数组中下标0的分量为表头结点,并令表头结点记录的关键字取最大整数MAXINT。表插入排序的基本操作仍然是将一个记录插入到已经排好序的有序表中,和直接插入排序有相似之处,不同之处在于是以修改2次指针值代替1次移动记录。
示意图
算法分析
时间复杂度仍然是n*n, 因为排序过程中需要和数据个数相同的指针值,所以辅助空间为n,是稳定的排序方法。
代码实现
见附录1
另外, 与表插入排序相关的还有一个重排算法, 先依旧从文字描述, 示意图, 复杂度和代码实现四方面分析该算法.
文字描述
表插入排序的结果只是求得一个有序链表,则只能对它进行顺序查找, 不能进行随机查找. 为了能实现有序表的折半查找,尚需对记录进行重新排列.
重排记录的做法是: 顺序扫描有序链表, 将链表中第i个结点移动至数组的第i个分量重. 若第i个最小关键字的结点是数组中下标为p且p>i的分量,则互换SL.r[i]和SL.r[p],且令SL.r[i]中指针域的值改为p; 由于此时数组中所有小于i的分量中已经是“到位”的分量,则当p<i时,应顺链继续查找直到p>i或p==i为止。
示意图
算法分析
在重排记录的过程中,最坏情况是每个记录到位都必须进行一次记录的交换,即3次移动记录,所以重排记录至多需进行3(n-1)次记录的移动, 它并不增加表插入排序的时间复杂度,还是n*n, 辅助空间为1
代码实现
见附录1
附录1
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 #define DEBUG 5 6 //静态链表容量 7 #define SIZE 100 8 //最大整数 9 #define MAX 100 10 11 #define EQ(a, b) ((a) == (b)) 12 #define LT(a, b) ((a) < (b)) 13 #define LQ(a, b) ((a) <= (b)) 14 15 //定义关键字类型为整数类型 16 typedef int KeyType; 17 //定义其它数据项为整数类型 18 typedef int InfoType; 19 20 //记录类型 21 typedef struct{ 22 //关键字项 23 KeyType key; 24 //其他数据项 25 InfoType otherinfo; 26 }RedType; 27 28 //表结点类型 29 typedef struct{ 30 //记录项 31 RedType rc; 32 //指针项 33 int next; 34 }SLNode; 35 36 //静态链表类型 37 typedef struct{ 38 //0号单元为表头结点 39 SLNode r[SIZE]; 40 //链表当前长度 41 int length; 42 }SLinkListType; 43 44 //顺序打印静态链表中的关键字和指向下个数据的指针 45 void PrintSList(SLinkListType SL){ 46 int i = 0; 47 printf("下标值:"); 48 for(i=0; i<=SL.length; i++){ 49 printf("[%d] ", i); 50 } 51 printf(" 关键字:"); 52 for(i=0; i<=SL.length; i++){ 53 printf(" %-4d", SL.r[i].rc.key); 54 } 55 printf(" 其他值:"); 56 for(i=0; i<=SL.length; i++){ 57 printf(" %-4c", SL.r[i].rc.otherinfo); 58 } 59 printf(" "); 60 return ; 61 } 62 63 //表插入排序算法 64 void TableInsertSort(SLinkListType *SL) 65 { 66 //0号位表头结点,存最大整数值MAX 67 SL->r[0].rc.key = MAX; 68 //首先将静态链表中数组下标为1的分量和表头结点构成一个循环链表 69 SL->r[0].next = 1; 70 SL->r[1].next = 0; 71 72 //和直接插入排序相似,只是不移动记录,只是改变指针指 73 int i = 0, q = 0, p = 0; 74 for(i=2; i<=SL->length; i++){ 75 q = 0; 76 p = SL->r[q].next; 77 while(LQ(SL->r[p].rc.key, SL->r[i].rc.key)){ 78 q = p; 79 p = SL->r[q].next; 80 } 81 //以修改2次指针值代替移动记录 82 SL->r[q].next = i; 83 SL->r[i].next = p; 84 } 85 return ; 86 } 87 88 /* 89 * 表插入排序相关的重排算法 90 * 91 * 根据静态链表SL中各结点的指针调整记录位置, 92 * 使得SL中各记录按关键字升序排序 93 * 94 */ 95 void Arrange(SLinkListType *SL) 96 { 97 //p指示第一个记录的当前位置 98 int p = SL->r[0].next, q = 0; 99 int i = 0; 100 SLNode tmp; 101 102 //SL.r[1..i-1]中记录已按关键字有序排列 103 for(i=1; i<SL->length; ++i){ 104 //第i个记录的在SL中的当前位置应不小于i 105 while(p<i){ 106 p = SL->r[p].next; 107 } 108 //q指示尚未调整的表尾 109 q = SL->r[p].next; 110 if(p != i){ 111 //交换记录,使第i个记录到位 112 tmp = SL->r[p]; 113 SL->r[p] = SL->r[i]; 114 SL->r[i] = tmp; 115 //指向被移走的记录,使得以后可由while循环找回 116 SL->r[i].next = p; 117 } 118 //p指示尚未调整的表尾,为找第i+1个记录作准备 119 p = q; 120 #ifdef DEBUG 121 printf("第%d趟重排: ", i); 122 PrintSList(*SL); 123 #endif 124 } 125 } 126 127 int main(int argc, char *argv[]) 128 { 129 if(argc < 2){ 130 return -1; 131 } 132 SLinkListType SL; 133 int i = 0; 134 for(i=1; i<argc; i++){ 135 if(i>SIZE) 136 break; 137 SL.r[i].rc.key = atoi(argv[i]); 138 SL.r[i].next = 0; 139 SL.r[i].rc.otherinfo = 'a'+i-1; 140 } 141 SL.length = (i-1); 142 SL.r[0].rc.key = 0; 143 SL.r[0].rc.otherinfo = '0'; 144 /*进行表插入排序*/ 145 TableInsertSort(&SL); 146 printf("表插入排序之后的静态链表: "); 147 PrintSList(SL); 148 149 /*重排记录,使它能满足有序表的折半查找*/ 150 Arrange(&SL); 151 return 0; 152 }
运行