1. 程式人生 > >C語言基數排序——順序佇列實現

C語言基數排序——順序佇列實現

基數排序

基本要求:

從鍵盤上輸入n個程度為m的整數,要求輸出這些整數的升序排列。

具體要求

  1. 使用的資料結構是佇列,利用順序佇列來實現
  2. 有良好的人機互動
  3. 能夠輸出每一趟分配和收集的情況

基本概念:

基數排序屬於分配式排序、又稱桶子法。通過鍵值的查詢,將要排序的元素分配至某些“桶”中,以達到排序的作用。

具體思想:

以整形為例,將整形10進位制按每位拆分,然後從低位到高位依次比較

主要分為兩個過程:

分配,先從個位開始,根據位值(0-9)分別放到0~9號桶中

收集,再將放置在0~9號桶中的資料按順序放到陣列中

重複分配收集過程,從個位到最高位為重複次數

程式碼實現:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define Radix 10          //代表Radix(10)個佇列

typedef int QElemType;
typedef struct
{
    QElemType *base;       //初始化的動態分配空間,儲存資料
    int front;              //頭指標,指向佇列頭元素,用來移動
    int rear;               //尾指標,指向佇列尾元素的下一位置,確定長度
} SqQueue;


//distribute進行第n趟分配
//原始資料儲存在Q.base陣列中
//ArrType是SqQueue型別的陣列,
void distribute(SqQueue &Q,int n,SqQueue ArrType[])
{
    //quot-商
    //rem-儲存每個資料的第n位(即第1位、第2位...第n位)的值
    int i,c,temp,quot,rem;
    //for置空Radix(10)個佇列
    for(i=0; i<Radix; i++)
        ArrType[i].front=0;
    //for處理每個資料的第n位
    for(i=0; i<Q.rear; i++)
    {
        //將第i個數據暫存到quot
        quot=Q.base[i];
        c=0;
        //while計算第i個數據的第n位的值並儲存到rem
        while(c<n)
        {
            c++;
            rem=quot%Radix;
            quot/=Radix;
        }
        //將第n位為rem的資料複製到第rem個佇列
        //即根據資料的第n位的數字rem,將資料分配到第rem個佇列的尾部
        ArrType[rem].base[ArrType[rem].front++]=Q.base[i];
    }
    printf("第%d趟分配之後的情況是:\n",n);
    for(i=0; i<Radix; i++)
    {
        temp=ArrType[i].front;
        //if如果第i個佇列不為空
        if(temp>0)
        {
            printf("佇列[%d]隊頭指標front->",i);
            for(c=0; c<temp-1; c++)
                printf("%d-",ArrType[i].base[c]);
            printf("%d<-佇列[%d]隊尾指標rear\n",ArrType[i].base[temp-1],i);
        }
    }
}

//collect進行第n趟收集
//ArrType儲存了第n-1趟分配的結果
void collect(SqQueue &Q,int n,SqQueue ArrType[])
{
    //collected記錄已收集資料的數量
    int i,collected=0;

    //for將陣列ArrType中的資料收集到int型陣列Q.base中
    for(i=0; i<Radix; i++)
    {
        //if如果第i個佇列不空,就收集它的資料
        if(ArrType[i].front!=0)
        {
            //進行收集(簡單地複製到Q.base陣列就行了)
            memcpy(Q.base+collected,ArrType[i].base,ArrType[i].front*sizeof(int));
            collected+=ArrType[i].front;
        }
    }
    printf("第%d趟收集之後的情況是:\n",n);
    for(i=0; i<=Q.front-1; i++)
    {
        printf("%d ",Q.base[i]);
    }
    printf("\n\n");
}

//計算每個佇列的初始長度(為資料量的1/Radix)
void Ord(SqQueue &Q,SqQueue ArrType[],int M)
{
    int i;
    int temp=M;

    for(i=0; i<Radix; i++)
    {
        //為第i個佇列分配空間
        ArrType[i].base=(int*)calloc(temp,sizeof(int));
        ArrType[i].rear=temp;
    }
}

//for進行M(M為輸入的每個資料的長度)趟分配和收集
void RadixSort(SqQueue Q,int M,SqQueue ArrType[])
{
    for(int i=1; i<=M; i++)
    {
        distribute(Q,i,ArrType);
        collect(Q,i,ArrType);
    }
}


int main()
{
    int i,M;
    SqQueue Q,ArrType[Radix];
    printf("請輸入每個資料的長度:");
    scanf("%d",&M);
    printf("請輸入共有多少個數據:");
    scanf("%d",&Q.rear);
    Q.base=(int*)calloc(Q.rear,sizeof(int));
    Q.front=0;
    printf("請輸入%d個長度為%d的資料:\n",Q.rear,M);
    for(i=0; i<Q.rear; i++)
        scanf("%d",&Q.base[Q.front++]);
    printf("\n");
    Ord(Q,ArrType,M);
    RadixSort(Q,M,ArrType);
    //以下的free釋放動態分配的記憶體
    free(Q.base);
    for(i=0; i<Radix; i++)
        free(ArrType[i].base);
    system("PAUSE");
    return 0;
}

資料處理:

尾言:

基數排序法是屬於穩定性的排序,其時間複雜度為O (nlog(r)m),其中r為所採取的基數,而m為堆數

在某些時候,基數排序法的效率高於其它的穩定性排序法。