箱排序,基數排序(C)

箱排序

1.例子和運行結果

例子:
在這裏插入圖片描述
運行結果:
在這裏插入圖片描述

2.排序思想

1.每個數都是由0-9組成,開始創建10個箱子(序號0-9).
2.對待排序進行遍歷,按照待排序個位數有序的添加對應箱子中,注意,是有序的添加.(這個可以使用快速排序,直接插入,選擇插入…等).
3.順序遍歷所有的箱子.然後順序的讀取箱子中的值,順序存儲到數組中,此時這個數組就是有序的數組

注意:這裏最多創建了10個箱子,如果知道了都是兩位數,也可以創建0-99號箱子,每個箱子後面添加對應的值.(這種方法不推薦,浪費內存)

3.算法實現

3.1定義數據結構

//箱子後面鏈接的順序表
typedef struct Seq{
    //順序的值,這裏最多存儲MAX個數,所以待排序數的也不可以超過MAX個.(擴展的基數排序中,用鏈表,就不用考慮個數了)
    int array[MAX];
    int length;//當前順序表的長度
}BoxSeq;

//箱子排序的Bean
typedef struct Box{
    int key;//排序的基數
    BoxSeq seq;//箱子中順序存儲的數據(有序添加)
}B;

這裏可以進行完善有兩點:
1.可以將Seq和Box合併成一個,這個爲了便於理解箱子的結構,所以這樣定義的
2.箱子中的列表可以使用鏈表進行存儲,這樣就不用限制待排序的數量.這個在下面擴展的基數排序算法中進行了修改.

3.2 定義操作方法

/打印箱子
void  logB(B box);
//往箱子中順序添加數值,遞增
void  addValueToBox(B *b,int  value);
//箱排序
void  BoxSort(void);

3.3方法實現


//打印箱子
void  logB(B box){
    int  i;
    printf("[%d]->[",box.key);
    for(i=0;i<box.seq.length;i++){
        if(i==0)
            printf("%d",box.seq.array[i]);
        else
            printf(",%d",box.seq.array[i]);
    }
    printf("]\n");
}

//往箱子中順序添加數值,遞增
void  addValueToBox(B *b,int value){
    //1.先找到插入的位置(找到第一個小於的value值的位置).
    //10,13,15,17,比如要插入14,那麼找到的位置就是2.
    int i=0;
    int j;
    while (i<b->seq.length&&b->seq.array[i]!=-1) {
        if(b->seq.array[i]<value)
            i++;
        else
            break;
    }
    
    //2.移動i位置之後(包含i位置)之後的值
    //10,13,14,15,17
    for(j=b->seq.length-1;j>=i;j--)
        b->seq.array[j+1]=b->seq.array[j];
    //3.將添加的值(value)添加到i位置
    b->seq.array[i]=value;
    //4.然後length+1
    b->seq.length=b->seq.length+1;
}

//箱排序
void  BoxSort(){
    int i;
    int count;
    int j;
    //1.初始化待排序的數組
    int array[MAX];//待排序的數組
    array[0]=88;
    array[1]=19;
    array[2]=13;
    array[3]=78;
    array[4]=43;
    array[5]=15;
    array[6]=22;
    array[7]=16;
    array[8]=83;
    array[9]=10;
    printf("待排序:");
    logArray(array, MAX);
    //2.因爲待排序的數組是0-100之間,所以我們定義10個箱子
    B boxs[MAX];//箱子列表
    //num存儲在箱子Bbox[num/10]中,添加的時候順序添加.
    //初始化箱子列表
    for(i=0;i<MAX;i++){
        boxs[i].key=i;
        boxs[i].seq.length=0;
        for(j=0;j<MAX;j++){
            boxs[i].seq.array[j]=-1;
        }
            
    }
    //3.遍歷待排序數組
    for(i=0;i<MAX;i++){
        int bnum=array[i]/10;
        //3.1.然後往對應的箱子中添加
        addValueToBox(&boxs[bnum],array[i]);
    }
    count=0;
    //4.遍歷箱子,組裝成有序數組
    for(i=0;i<MAX;i++){
        //4.1如果此時的箱子長度不爲空
        //打印所有箱子中的數據
        logB(boxs[i]);
        if(boxs[i].seq.length>0){
        //4.2.遍歷當前箱子然後順序輸出,添加到數組中
            for(j=0;j<boxs[i].seq.length;j++)
                array[count++]=boxs[i].seq.array[j];
        }
    }
    //5.打印排序好的數組
    printf("已排序:");
    logArray(array, MAX);
}

3.5公共方法

//打印數組
void  logArray(int array[],int length);

//打印數組
void  logArray(int array[],int length){
    int  i;
    printf("[");
    for(i=0;i<length;i++){
        if(i==0)
            printf("%d",array[i]);
        else
            printf(",%d",array[i]);
    }
    printf("]\n");
}

基數排序

1.例子和運行結果

例子:
在這裏插入圖片描述
運行結果:
在這裏插入圖片描述

2.排序思想

1.基數排序是在箱排序的基礎之上進行擴展和完善的
2.通過判斷待排序的數組中的位數,決定進行創建箱子的個數和遍歷的次數.
例如:待排序中最多的位數爲3位,那麼就需要創建三個箱子(當然也可以創建兩個,進行復用,記得複用之前要清除之前的箱子),這裏我就不復用了.那麼需要進行遍歷三次
3.開始排序(就是遍歷裝箱操作)
3.1:第一次遍歷待排序的數組.進行第一次裝箱(箱子A),按照個數進行裝到對應的箱子.
3.2:第二次順序遍歷前面的箱子(箱子A),進行第二次裝箱(箱子B),按照十位數進行裝到對應的箱子中.
3.3:第三次順序遍歷前面的箱子(箱子B),進行第三次裝箱(箱子C),按照百位數進行裝到對應的箱子中.

到了這裏已經排序完成,還差最後一步.
4.組裝數據,順序遍歷最後一次的箱子(箱子C).存儲到一個數組中,此時數組中的數據就是已經排序好的.

在這裏插入圖片描述
例如:上面的箱子,順序遍歷這個箱子A存儲到箱子B中.(按照十位存儲)
讀取0號桶:
第一個數:200, 十位爲0, 存儲箱子B中0號桶[200]
第二個數:100, 十位爲0, 存儲箱子B中0號桶[200,100]
讀取1號桶:
第一個數:211, 十位爲1, 存儲箱子B中1號桶[211]
讀取2號桶:
沒有值跳過
讀取3號桶:
第一個數:143, 十位爲4, 存儲箱子B中4號桶[143]
第二個數:433, 十位爲3, 存儲箱子B中3號桶[433]
讀取4號桶:
第一個數:84, 十位爲4, 存儲箱子B中8號桶[84]
第二個數:134, 十位爲3, 存儲箱子B中3號桶[433,134]
第三個數:534, 十位爲3, 存儲箱子B中3號桶[433,134,534]
第四個數:994, 十位爲9, 存儲箱子B中9號桶[994]
…後面的就不一一舉例了.直到遍歷結束.

3.算法實現

3.1定義數據結構

#define  MAX_COUNT 10

//鏈表結點 順序存儲箱子中數值,這樣就可以不用限制數據量.
typedef struct SNode{
    int  value;
    struct SNode * next;
}Node;
//箱子中的每個鏈表
typedef struct List{
    int key;
    Node *header;//頭指針
    Node *rear;//尾指針
}LinkList;
//箱子列表
typedef struct RadixBox{
    LinkList * boxs[MAX_COUNT];
}RB;

3.2 定義方法


//入隊
void InsertList(LinkList *list,int value);
//打印隊列
void logList(LinkList *list);
//打印箱子
void  logRadixBox(RB rb);
//打印箱子--數組類型
void  logRadixBoxArray(RB rb);
//裝箱操作
//type:1->除數爲1*10  2:除數爲2*20
void EnRadixBox(int type,RB rb,int value);
//基數排序
void  RadixSort(void);

下載的源碼中少了這個方法:logRadixBoxArray(),可以添加上,也可以不加,這是多打印了每次裝箱後的數組.

3.3方法實現


//打印隊列
void logList(LinkList *list){
    //先判斷列表是否爲空
    if(list!=NULL){
        Node *p=list->header;
        printf("[");
        int first=1;
        while (p!=NULL) {
            if(first==1){
                first=0;
                printf("%d",p->value);
            }else{
                printf(",%d",p->value);
            }
            p=p->next;
        }
        printf("]\n");
    }
}

//打印箱子
void  logRadixBox(RB rb){
    printf("********************************\n");
    int  i;
    for(i=0;i<MAX_COUNT;i++){
        printf("[%d]->",rb.boxs[i]->key);
        logList(rb.boxs[i]);
    }
    logRadixBoxArray(rb);
    printf("********************************\n");
}
//打印箱子--數組類型
void  logRadixBoxArray(RB rb){
    Node  *p;
    int i=0;
    int  j;
    printf("裝箱後的數組:[");
     for(j=0;j<MAX_COUNT;j++){
         p= rb.boxs[j]->header;
         while (p!=NULL) {
             if(i==0)
             {
                 printf("%d",p->value) ;
                 i=1;
             }
             else
               printf(",%d",p->value) ;
            p=p->next;
         }
     }
      printf("]\n");
}

//入隊
void InsertList(LinkList *list,int value){
    //1.創建插入的結點
    Node *p=(Node *)malloc(sizeof(Node));
    p->value=value;
    p->next=NULL;
    //2.判斷鏈表是否爲NULL
    if(list==NULL){
        list=(LinkList *)malloc(sizeof(LinkList));
        list->header=NULL;
        list->rear=NULL;
    }
    //3.將新的結點插入鏈表
    if(list->header==NULL){
        list->header=p;
    }
    if(list->rear==NULL){
       list->rear=p;
    }else{
        list->rear->next=p;
        list->rear=p;
    }
}

//裝箱操作
//type->0:個數,1:十位,2:百位的餘數
void EnRadixBox(int type,RB rb,int value){
    //1.type必須從1開始
    if(type<0){
        return;
    }
    //2.計算位置
    //134: 134%10
    //134: (134/10)%10
    //134: (134/100)%10
    //(value/(pow(10,type)))%10
    int position= ((int) (value/(int)pow(10, type)))%10;
    LinkList *list= rb.boxs[position];
    InsertList(list,value);
}

//基數排序
void  RadixSort(void){
    int i;
    int j;
    int n=19;
    //1.初始化待排序的數組
    int array[]={76,84,134,196,177,143,696,534,599,211,433,200,994,459,635,179,100,26,284};
    printf("未排序:");
    logArray(array, n);
    //2.首先要知道數組中最大的是幾位數,就需要幾個箱子,從個位到最高位順序裝箱
    //初始化箱子
    RB rbs[3];
    //初始化三個箱子
    for(i=0;i<3;i++){
        for(j=0;j<MAX_COUNT;j++){
            rbs[i].boxs[j]=(LinkList *)malloc(sizeof(LinkList));
            rbs[i].boxs[j]->key=j;
            rbs[i].boxs[j]->header=NULL;
            rbs[i].boxs[j]->rear=NULL;
        }
    }
    //3.開始裝箱
    for(i=0;i<3;i++){
        if(i==0){//第一次是遍歷排序數組,裝箱
            for(j=0;j<n;j++){
                //個位
                EnRadixBox(i,rbs[i],array[j]);
            }
            logRadixBox(rbs[i]);
        }else{//之後就是遍歷前一個箱子進行裝箱
            //遍歷前一個箱子,裝在當前箱子
           RB rbPre=rbs[i-1];
            for(j=0;j<MAX_COUNT;j++){
                if(rbPre.boxs[j]!=NULL){
                    Node *p=rbPre.boxs[j]->header;
                    while (p!=NULL) {
                        EnRadixBox(i,rbs[i],p->value);
                        p=p->next;
                    }
                }
            }
           logRadixBox(rbs[i]);
        }
    }
    //4.遍歷最後一個箱子裝入數組,就是排好序的
    Node  *p;
    i=0;
     for(j=0;j<MAX_COUNT;j++){
         p= rbs[2].boxs[j]->header;
         while (p!=NULL) {
             array[i++]=p->value;
             p=p->next;
         }
     }
      printf("已排序:");
      logArray(array, n);
}

3.4 另外的實現思路

我這裏循環遍歷的時候,第一次是遍歷待排序的數據,然後進行裝箱,剩下的順序遍歷,是遍歷上一次的箱子.
優化點:
1.創建箱子的時候,可以創建一個個箱子
2.每次裝完箱子操作後,可以先順序遍歷箱子,順序存儲到數組中.然後下一次遍歷的時候,是遍歷裝箱後的數組.這樣就是每次都是遍歷數組,進行裝箱.
3.在決定循環幾次的時候,我這裏知道待排序中的數組,最大的是3位數,
3.1這裏可以寫一個快速查找方法,尋找最大位數,或者最大值.
3.2或者是在第一次裝箱的時候,同時查找最大位數(N)也可以,這樣後面循環的就是再進行(N-1)次.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章