插入排序包括直接插入排序和改进的折半插入排序、2-路插入排序、表插入排序和希尔排序。
折半插入排序可减少关键字间的比较次数,记录的移动次数不变;
2-路插入排序目的是减少排序过程中的移动次数,为此需要N个记录的辅助空间;
表插入排序则可以完全避免记录的移动,但因比较次数一样,时间复杂度仍不变;
希尔排序又称“缩小增量排序”,其基本思想为:先将整个待排记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录基本有序时,再对全体记录进行一次直接插入排序。
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#define MAXSIZE 20
typedef int KeyType;
typedef int InfoType;
typedef struct
{
KeyType key;
InfoType otherinfo;
}RedType;
typedef struct
{
RedType r[MAXSIZE+1];
int length;
}SqList;
/*静态链表数据结构*/
#define SIZE 100
typedef struct
{
KeyType rc;
int next;
}SLNode;
typedef struct
{
SLNode r[SIZE];
int length;
}SLinkList;
void InsertSort(SqList *L);
int LT(KeyType a,KeyType b);
void BInsertSort(SqList *L);
void BnInsertSort(SqList *L);
void SLListSort(SLinkList *SL);
void Arrange(SLinkList *SL);
void ShellInsert(SqList *L,int dk);
void ShellSort(SqList *L,int dlta[],int t);
int main()
{
SqList *L,*L1,*L2,*L3,*L4;
L=(SqList *)malloc(sizeof(SqList));
L1=(SqList *)malloc(sizeof(SqList));
L2=(SqList *)malloc(sizeof(SqList));
L3=(SqList *)malloc(sizeof(SqList));
L4=(SqList *)malloc(sizeof(SqList));
SLinkList *SL;
SL=(SLinkList *)malloc(sizeof(SLinkList));
int i;
printf("需排序的项数为:");
scanf("%d",&L->length);
SL->length=L->length; /* 为静态链表赋长度*/
for(i=0;i<L->length;i++)
{
printf("please input the number:");
scanf("%d",&L->r[i+1].key);
SL->r[i+1].rc=L->r[i+1].key; /* 为静态链表赋值*/
}
*L1=*L2=*L3=*L4=*L;
int dlta[5]={0},t;
printf("请输入增量序列长度:");
scanf("%d",&t);
printf("请输入增量序列:");
for(i=0;i<t;i++)
scanf("%d",&dlta[i]);
ShellSort(L4,dlta,t);
printf("the result is:");
for(i=0;i<L4->length;i++)
{
printf("%d ",L4->r[i+1].key);
}
printf("\n");
SLListSort(SL);
Arrange(SL);
InsertSort(L1);
BInsertSort(L2);
BnInsertSort(L3);
printf("the result is:");
for(i=0;i<L1->length;i++)
{
printf("%d ",L1->r[i+1].key);
}
printf("\n");
for(i=0;i<L2->length;i++)
{
printf("%d ",L2->r[i+1].key);
}
printf("\n");
for(i=0;i<L3->length;i++)
{
printf("%d ",L3->r[i+1].key);
}
printf("\n");
return 0;
}
int LT(KeyType a,KeyType b)
{
return a<b;
}
/*直接插入排序*/
/*基本操作是将一个记录插入到已排好序的有序表中,*/
/*其默认第一个记录为已排好序,依次选择后面的与前面的有序列的最后一项比较*/
void InsertSort(SqList *L)
{
int i,j,count;
count=0;
for(i=2;i<=L->length;i++)
{
if(LT(L->r[i].key,L->r[i-1].key)) /*如果待排序项比已排序队列最后一项小,则进行以下操作,否则跳过。*/
{
L->r[0]=L->r[i]; /*先将待排序项保存在哨兵中*/
count++;
L->r[i]=L->r[i-1]; /*将比待排项大的前一项后移*/
count++;
for(j=i-2;LT(L->r[0].key,L->r[j].key);j--) /*如果前面的项还是比待排项大,则一直往后移一位*/
{
count++;
L->r[j+1]=L->r[j];
}
L->r[j+1]=L->r[0]; /*将保存在哨兵项里的待排项放到正确的位置*/
count++;
}
}
printf("\n直接插入排序移动了%d次。\n",count);
}
/*折半插入排序*/
/*对已排序项进行折半查找,找到该插入的位置*/
void BInsertSort(SqList *L)
{
int i,count;
count=0;
for(i=2;i<=L->length;i++)
{
int j,low,high,m;
L->r[0]=L->r[i];
count++;
low=1;
high=i-1;
/*while循环最终次是low==high,*/
while(low<=high)
{
m=(low+high)/2;
if(LT(L->r[0].key,L->r[m].key))
high=m-1;
else
low=m+1;
}
/*循环的最终结果是该插入位置为high+1,在此之前将该位置及其后的项往后移一步*/
for(j=i-1;j>=high+1;j--)
{
count++;
L->r[j+1]=L->r[j];
}
L->r[high+1]=L->r[0];
count++;
}
printf("\n折半插入排序移动了%d次。\n",count);
}
/*2-路插入排序*/
/*另设一数组D,首先将L.r[1]赋值给D[1],并将D[1]看成是在排好序的序列中的中间项*/
/*然后从L.r中的第2个记录开始,依次插入到D[1]之前或之后的有序表中*/
void BnInsertSort(SqList *L)
{
RedType *D;
D=(RedType *)malloc(sizeof(RedType)*L->length);
D[0]=L->r[1];
int count=0;
int i,j,min,max;
min=max=0;
for(i=2;i<=L->length;i++)
{
if(L->r[i].key>=D[max].key)
{
max++;
D[max]=L->r[i];
}
else if(L->r[i].key<=D[min].key)
{
min=(min+L->length-1)%L->length;
D[min]=L->r[i];
}
else if(L->r[i].key>=D[0].key)
{
for(j=max;L->r[i].key<D[j].key;j--)
{
count++;
D[j+1]=D[j];
}
max++;
D[++j]=L->r[i];
}
else
{
for(j=min;L->r[i].key>D[j].key;j++)
{
count++;
D[j-1]=D[j];
}
min--;
D[--j]=L->r[i];
}
}
for(i=1;i<=L->length;i++)
{
L->r[i]=D[min++%L->length];
}
printf("\n2-路插入排序移动了%d次。\n",count);
}
/*表插入排序*/
/*基本操作仍是将一个记录插入到已排好序的有序表中,与直接插入相比,区别是以修改2n次指针代替移动*/
/*但比较次数相同,因此时间复杂度相同*/
void SLListSort(SLinkList *SL)
{
/*先将表头和下标为1的项构成循环链表*/
SL->r[0].rc=INT_MAX;
SL->r[0].next=1;
SL->r[1].next=0;
int i;
for(i=2;i<=SL->length;i++)
{
int cur,next;
cur=0;
next=SL->r[cur].next;
while(SL->r[i].rc>SL->r[next].rc)
{
cur=next;
next=SL->r[next].next;
}
SL->r[i].next=SL->r[cur].next;
SL->r[cur].next=i;
}
printf("链表排序结果:");
for(i=SL->r[0].next;SL->r[i].rc<SL->r[0].rc;i=SL->r[i].next)
printf(" %d ",SL->r[i].rc);
printf("链表为:\n");
printf("key: ");
for(i=0;i<=SL->length;i++)
printf(" %2d ",SL->r[i].rc);
printf("\nnext:");
for(i=0;i<=SL->length;i++)
printf(" %2d ",SL->r[i].next);
}
/*对排序后的静态链表进行重排*/
/*具体做法为:顺序扫描有序链表,将链表中第i个结点移动至数组的第i个分量中*/
void Arrange(SLinkList *SL)
{
int i,p,q;
p=SL->r[0].next;
for(i=1;i<SL->length;i++)
{
while(p<i)
p=SL->r[p].next;
q=SL->r[p].next;
if(p!=i)
{
SLNode *t;
t=(SLNode *)malloc(sizeof(SLNode));
*t=SL->r[p];
SL->r[p]=SL->r[i];
SL->r[i]=*t;
SL->r[i].next=p;
}
p=q;
}
printf("链表为:\n");
printf("key: ");
for(i=0;i<=SL->length;i++)
printf(" %2d ",SL->r[i].rc);
printf("\nnext:");
for(i=0;i<=SL->length;i++)
printf(" %2d ",SL->r[i].next);
}
/*希尔排序:*/
/*基本思想:先将整个待排记录序列分割成为若干子序列分别进行直接插入排序,*/
/*待整个序列中的记录“基本有序”时,再对全体记录进行一次直接插入排序。*/
/*特点是:子序列的构成不是简单地“逐段分割”,而是将相隔某个增量的记录组成一个子序列*/
void ShellInsert(SqList *L,int dk)
{
int i,j;
for(i=dk+1;i<=L->length;i++)
{
if(LT(L->r[i].key,L->r[i-dk].key))
{
L->r[0]=L->r[i];
for(j=i-dk;j>0&<(L->r[0].key,L->r[j].key);j-=dk)
L->r[j+dk]=L->r[j];
L->r[j+dk]=L->r[0];
}
}
}
/*增量序列的值必须没有除1之外的公因子,并且最后一个增量值必须等于1*/
void ShellSort(SqList *L,int dlta[],int t)
{
int k;
for(k=0;k<t;k++)
ShellInsert(L,dlta[k]);
}
/**/