1、前面文章介绍的插入排序不可避免地要移动记录,而表插入排序则不需要移动记录。


2、待排序数据的常用存储方式有:

(1)以顺序表作为存储结构:对记录本身进行物理重排,即通过关键字之间的比较判定,将记录移到合适的位置;

(2)以链表作为存储结构:无需移动记录,仅需修改指针。通常将这类排序称为链表(或链式)排序;

(3)用顺序的方式存储待排序的记录,但同时建立一个辅助表(如包括关键字和指向记录位置的指针组成的索引表)

只需对辅助表进行物理重排,即只移动辅助表的表目,而不移动记录本身。适用于难于在链表上实现,仍需避免排序

过程中移动记录的排序方法。表插入排序即属于这种情况。


3、表插入排序的过程可以描述为将存储结构由顺序结构改为链式结构,再进行插入排序,链式结构在插入时无需移

动记录,只需修改指针值。和直接插入排序算法相比较,表插入排序中比较的关键字次数不变,只是需要n个辅助空

间来存放每个数据的指针值。由此推知的时间复杂度为O(n2)。也就是说,表插入排序算法是通过减少"移动"次数来对

直接插入排序的改进。


4、下面提供两种代码示例:

(1)一些定义(有一些定义在前一篇文章,这里不再重复):


typedef        struct      


       {      


              RedType rc;        // 记录项      


              int        next;         // 新增用于实现表排序的指针域      


              


       }RecNode;          // 表结点的类型      


              


       typedef        struct      


       {      


              RecNode R[MAXSIZE + 1];         // 0号元素不存放有效数据,而是用作头结点      


              int        Length;                       // 链表的当前长度      


              


       }SLinkList;        // 静态链表的类型


(2)实现一:


void        TableInsertSort1(SLinkList* L)      


       {      


              int        i;      


              int        j;      


              int        p;      


              int        head;      


              


              // 表头结点记录的关键字取最大整数以当作观察哨(非降序表的表尾)      


              L->R[0].rc.key = numeric_limits<KeyType>::max();      


              


              // 从第1个有效数据元素开始插入      


              i=L->R[0].next;      


              


              // next域为0表示表尾(现为空表)      


              L->R[0].next=0;      


              


              // 当有未插入元素时反复进行插入排序操作      


              while       (i!=0)      


              {             


              head = 0;                    // 待插入结点的前驱结点下标          


              p = L->R[0].next;         // 待插入结点下标      


              


              // 找合适插入位置      


              while       (L->R[i].rc.key > L->R[p].rc.key)      


              {      


              head = p;      


              p = L->R[p].next;      


              }      


              


              j = L->R[i].next;         // 取下一条记录      


              L->R[i].next = p;         // 将当前记录插入到静态链表      


              L->R[head].next = i;      


              


              i = j;      


              }      


       }


(3)实现二:


void        TableInsertSort2(SLinkList *L)      


       {      


              int        p;      


              int        head;        


              


              //初始化        


              L->R[0].next = 1;        


              L->R[1].next = 0;        


              


              //逐个插入        


              for       (       int        i = 2; i <= L->Length; i++)      


              {        


              head = 0;        


              p = L->R[0].next;        


              


              // 遍历链表,寻找插入位置        


              while       (p != 0 && L->R[p].rc.key <= L->R[i].rc.key)      


              {        


              head = p;        


              p = L->R[p].next;        


              }        


              


              // 插入的值是最大值        


              if       (p == 0)      


              {      


              L->R[i].next = p;        


              L->R[head].next = i;        


              }      


              else      


              {        


              L->R[i].next = p;        


              L->R[head].next = i;        


              }        


              }  


5、注意:表插入排序的结果只是求得一个有序的链表,因此只能对其进行顺序查找,而不能进行随机查找,为了实现有序表的折半查找,还需对记录进行重新排列。


6、给出一个调用示例:


int        _tmain(       int        argc, _TCHAR* argv[])      


       {      


              SLinkList L;      


              


              srand       ( (unsigned)        time       ( NULL ));      


              L.Length = MAXSIZE;      


              L.R[0].next = 1;                 // R[0]为头结点,其后继结点下标为1      


              for       (       int        i = 1;i <= L.Length; i++)      


              {      


              L.R[i].rc.key =        rand       () % 100;      


              L.R[i].next = i + 1;           // i号结点的后继结点下标为i+1      


              }      


              L.R[L.Length].next = 0;              // 末结点的指针域置为0以作为结束标记      


              


              


              int        p = L.R[0].next;      


              while       (p!=0)      


              {      


              cout << L.R[p].rc.key <<        "\t"       ;      


              p = L.R[p].next;      


              }      


              


              // 排序      


              TableInsertSort1(&L);      


              


              


              p = L.R[0].next;      


              while       (p!=0)      


              {      


              cout << L.R[p].rc.key <<        "\t"       ;      


              p = L.R[p].next;      


              }      


              


              getchar       ();      


              return        0;      


       }