2-路插入排序是对折半插入排序的改进,以减少排序过程中移动记录的次数。附加 个记录的辅助空间,方法是:
① 另设一个和L->R
同类型的数组d
,L->R[1]
赋给d[1]
,将d[1]
看成是排好序的序列中中间位置的记录;
② 分别将L->R[ ]
中的第i
个记录依次插入到d[1]
之前或之后的有序序列中,具体方法:
L->R[i].key < d[1].key
:L->R[i]
插入到d[1]
之前的有序表中;L->R[i].key ≥ d[1].key
:L->R[i]
插入到d[1]
之后的有序表中;
关键点:实现时将向量d
看成是循环向量,并设两个指针first
和final
分别指示排序过程中得到的有序序列中的第一个和最后一个记录。
示例:设有初始关键字集合{49, 38, 65, 13, 97, 27, 76} ,采用2-路插入排序的过程如右图10-3所示。
当L->R[1]
是待排序记录中关键字最大或最小的记录时,2-路插入排序就完全失去了优越性。
完整代码如下:
#include <stdio.h>
#define TRUE 1 //真
#define FALSE 0 //假
#define OK 1 //通过
#define ERROR 0 //错误
#define MAXSIZE 20 //用作示例的顺序表的最大长度
#define LT(a,b) ((a)<(b))
#define LQ(a,b) ((a)<=(b))
typedef int Status;
/* 记录类型 */
typedef int KeyType; //定义关键字类型为整数类型
typedef struct //顺序表结构
{
KeyType key; //关键字项
//使用结构体便于使用中扩展
}RcdType;
/* 顺序表类型 */
typedef struct
{
RcdType r[MAXSIZE+1]; //r[0]闲置或用作哨兵单元
int length; //顺序表长度
}SqList_sort;
//1.创建一个任意顺序的序列。
Status CreateSortList(SqList_sort *L)
{
printf("请输入元素个数:");
scanf("%d", &((*L).length));
if((*L).length > MAXSIZE)
return ERROR;
printf("请依次输入元素的关键字:\n");
for(int i = 1; i <= (*L).length; i++)
scanf("%d", &((*L).r[i].key));
return OK;
}
//2.输出序列L。
void Traverse(SqList_sort L)
{
for(int i = 1; i <= L.length; i++)
printf("%d ", L.r[i].key);
printf("\n");
}
//3. 对顺序表L作2-路插入排序。
void TwoTayInsertSort(SqList_sort *L)
{
int first, final, i, j;
RcdType d[MAXSIZE]; //从0号单元开始存储
if((*L).length>0)
{
d[0] = (*L).r[1];
first = final = 0;
}
for(i = 2; i <= (*L).length; i++)
{
if(LT((*L).r[i].key, d[first].key))
{
first = (first-1+MAXSIZE)%MAXSIZE;
d[first] = (*L).r[i];
}
else if(LT((*L).r[i].key, d[final].key))
{
j = final;
do
{
d[(j+1)%MAXSIZE] = d[j];
j = (j-1+MAXSIZE)%MAXSIZE;
}while(LT((*L).r[i].key, d[j].key));
d[(j+1)%MAXSIZE] = (*L).r[i];
final = (final+1)%MAXSIZE;
}
else
{
final = (final+1)%MAXSIZE;
d[final] = (*L).r[i];
}
}
for(i = 1, j = first; i <= (*L).length; i++, j = (j+1)%MAXSIZE)
(*L).r[i] = d[j];
}
int main(int argc, char *argv[])
{
SqList_sort L;
CreateSortList(&L);
TwoTayInsertSort(&L);
Traverse(L);
printf("\n");
return 0;
}