排序算法之直接插入排序、折半插入排序、2-路插入排序、表插入排序和希尔排序

插入排序包括直接插入排序和改进的折半插入排序、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&&LT(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]);
}
/**/

猜你喜欢

转载自blog.csdn.net/weixin_43213382/article/details/89278485