排序算法(七)表插入排序
原创
©著作权归作者所有:来自51CTO博客作者wwkaven的原创作品,请联系作者获取转载授权,否则将追究法律责任
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;
}
|