撲克牌排序:基於基數排序的方法

万俟麻木發表於2012-12-04

拿到這個問題,我首先想到的是:一個完全不懂程式設計的人碰到這個問題,他會怎麼做? 我覺得,一般人會把根據花色分成四堆,然後分別排序(這裡怎麼排每個人就會有不同的方法了),最後再收集起來。這個思想就很類似於基數排序了。

基數排序是比較穩定而且相對高效率的排序演算法。於是我就用基數排序實現了。
先根據點數分成13堆,收集起來,再根據花色分成4堆,再收集,就okay了。

值得一提的是,我必須使用連結串列來組織牌堆,因為如果用陣列的話,用基排就有“直接計算下標”的嫌疑,就犯規了;而現實中整理撲克的時候,我們的桌子上並沒有52個格子,來讓你排放撲克牌,所以用連結串列來表示還是比較符合實際情況的……實際上,這個問題其實還是直接根據牌面計算下標最快——但是規則不允許這麼做——所以我們實際上是在尋找儘可能快但是不能是最快的演算法。但是如果把問題改成“排序缺失了若干張未知牌的一副撲克”,就不存在這個問題了。而使用連結串列的基數排序仍然可以解決——所以我說了這麼多,用意其實是在於說明,我沒有犯規……

以下是C語言程式碼:

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

typedef struct poker poker;

struct poker{
    int suit;//0-spade, 1-heart, 2-flower, 3-box;
    int number;//J-11, Q-12, K-13, A-14;
    poker* next;
};

int _random(x){
    srand((int)time(0));
    return rand()%x;
}

poker* create_pile(){
    int n, i;
    int a[52];
    for(i = 0; i < 52; i++)
        a[i] = i;
    poker* pile = 0;
    for(n = 52; n > 0; n--){
        int t = _random(n);
        poker* p = malloc(sizeof(poker));
        p->suit = a[t]/13;
        p->number = a[t]%13 + 2;
        p->next = pile;
        pile = p;
        a[t] = a[n-1];
    }
    return pile;
}

poker* sort(poker* pile){
    poker* head[13];
    poker* tail[13];
    int i;
    for(i = 0; i < 13; i++){
        head[i] = tail[i] = 0;
    }
    //first round allocate;
    while(pile != 0){    
        poker* p = pile;
        pile = pile->next;
        p->next = 0;

        int number = p->number;
        if(tail[number-2] == 0){
            head[number-2] = tail[number-2] = p;
        }
        else{
            tail[number-2]->next = p;
            tail[number-2] = p;
        }
    }
    //collect;
    pile = head[0];
    for(i = 0; i < 12; i++){
        tail[i]->next = head[i+1];
        head[i] = tail[i] = 0;
    }
    //second round allocate;
    while(pile != 0){    
        poker* p = pile;
        pile = pile->next;
        p->next = 0;

        int suit = p->suit;
        if(tail[suit] == 0){
            head[suit] = tail[suit] = p;
        }
        else{
            tail[suit]->next = p;
            tail[suit] = p;
        }
    }
    //collect;
    pile = head[0];
    for(i = 0; i < 3; i++){
        tail[i]->next = head[i+1];
        head[i] = tail[i] = 0;
    }
    return pile;
}

int main(){
    poker* pile = create_pile();
    poker* p = pile;
    printf("Before sorted:\n");
    while(p != 0){
        printf("%d, %d\n", p->suit, p->number);
        p = p->next;
    }
    printf("=============\nAfter sorted:\n");
    pile = sort(pile);
    p = pile;
    while(p != 0){
        printf("%d, %d\n", p->suit, p->number);
        p = p->next;
    }
    return 0;
}

關於基數排序的介紹

相關文章