2016-10-16 76 views
2

我正在使用qsort對結構數組進行排序,並且我正在尋找一種更高效的方法,通過對數組進行部分排序來提取排名前三的最高分數。我的結構是這樣的:高效地對結構數組進行排序

typedef struct { 
    double score; 
    int player_num; 
} player_t; 

,我已經malloced結構數組是這樣的:

player_t *players = malloc(SIZE * sizeof(player_t)); 

的方式我有點這個數組結構的是,首先分揀分數,如果分數有聯繫,然後按玩家號碼排序。

我的代碼看起來是這個qsort

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

#define SIZE 6 
#define MAX 3 

int scorecmp(const void *a, const void *b); 
int ComparePlayerScore(const void* ap , const void* bp); 
int CompareInt(const int a , const int b); 

typedef struct { 
    double score; 
    int player_num; 
} player_t; 

int 
main(int argc, char *argv[]) { 
    int i; 

    int player_numbers[] = {1, 2, 3, 4, 5, 6}; 
    double scores[] = {0.765, 0.454, 0.454, 0.345, 0.643, 0.532}; 

    player_t *players = malloc(SIZE * sizeof(player_t)); 

    for (i = 0; i < SIZE; i++) { 
     players[i].score = scores[i]; 
     players[i].player_num = player_numbers[i]; 
    } 

    qsort(players, SIZE, sizeof(*players), ComparePlayerScore); 

    for (i = 0; i < MAX; i++) { 
     printf("Player %d: Score: %.3f\n", players[i].player_num, players[i].score); 
    } 

    free(players); 

    return 0; 
} 

int ComparePlayerScore(const void* ap , const void* bp) { 
    const player_t* const a = ap; 
    const player_t* const b = bp; 

    if(a->score == b->score){ 
     return CompareInt(a->player_num , b->player_num); 
    } 
    else if(a->score > b->score) { 
     return -1; 
    } 
    else { 
     return 1; 
    } 
} 

int CompareInt(const int a , const int b) { 
    if(a < b){ 
     return -1; 
    } 
    else if(a > b){ 
     return 1; 
    } 

    return 0; 
} 

我只是在尋找另一種方式來做到這一點,但更有效的方法來提取前3名的成績,與各玩家數字一起。就像我可以提取數組的前三個元素一樣,而不必每次都先排序整個數組。

+1

我想這是一個後續的[最近回答問題(http://stackoverflow.com/questions/40061974/partially-sorting-an-array -C)。 –

+0

是的,我一直在試驗這個,並試圖使它與'qsort'一起工作,但我似乎無法做到這一點,沒有先排序整個數組。看起來使用一系列結構會讓它變得更加困難。 – RoadRunner

+1

我會說不要擔心在這個級別的表現。你的數組只有大小6,所以不值得優化掉可能是多餘的三個比較。保持你的代碼簡單。而且,如果你後來有_measured_這個程序的這部分是最慢的,那麼你應該優化它。 –

回答

1

只是一個簡單的嘗試,請參閱在線演示http://ideone.com/8A1lnP

struct top3_players { 
    player_t *top[3]; 
}; 

void top3_determine(struct top3_players *top, player_t *players, size_t n) { 
    player_t *top1 = NULL; 
    player_t *top2 = NULL; 
    player_t *top3 = NULL; 
    for (size_t i = 0; i < n; i++) { 
    player_t *player = &players[i]; 
    if (top1 == NULL || ComparePlayerScore(player, top1) < 0) { 
     top3 = top2; 
     top2 = top1; 
     top1 = player; 
    } else if (top2 == NULL || ComparePlayerScore(player, top2) < 0) { 
     top3 = top2; 
     top2 = player; 
    } else if (top3 == NULL || ComparePlayerScore(player, top3) < 0) { 
     top3 = player; 
    } 
    } 
    top->top[0] = top1; 
    top->top[1] = top2; 
    top->top[2] = top3; 
} 
+0

虛擬比較器在某種程度上受教育嗎? –

+0

不,這只是爲了讓我的代碼可以自行編譯,當我將它粘貼到ideone時。我刪了它。 –

2

這是我的產品。既然你有#define MAX你想找到多少個最高分數,我已經考慮過了。

程序對數據進行一次傳遞,對每個記錄進行一次最頂層傳遞。我已經使用了一個固定陣列,你必須適應你的需求。

#include <stdio.h> 

#define SIZE 6 
#define MAX 3 

typedef struct { 
    double score; 
    int player_num; 
} player_t; 

int main(int argc, char *argv[]) 
{ 
    player_t players[SIZE] = {{2.0, 2}, {4.0, 5}, {1.0, 4}, {1.0, 1}, {5.0, 3}, {4.0, 6}}; 
    int order[MAX+1] = {0}; 
    int found = 1; 
    int i, j; 
    int bigger; 

    for(i = 1; i < SIZE; i++) { 
     bigger = 0; 
     for(j = 0; j < found; j++) { 
      if(players[i].score > players[ order[j] ].score) { 
       bigger = 1; 
       break; 
      } 
      else if(players[i].score == players[ order[j] ].score && 
        players[i].player_num < players[ order[j] ].player_num) { 
       bigger = 1; 
       break; 
      } 
     } 
     if(bigger) { 
      memmove(order + j + 1, order + j, (found - j) * sizeof order[0]); 
      order[j] = i; 
      if(found < MAX) { 
       found++; 
      } 
     } 
    } 

    for(i = 0; i < found; i++) { 
     printf("%d %f\n", players[ order[i] ].player_num, players[ order[i] ].score); 
    } 
    return 0; 
} 

程序輸出:

3 5.000000 
5 4.000000 
6 4.000000 
1

下面是通過存儲指向他們跟蹤前三名的成績的一個解決方案。添加播放器或更改分數時,會調用更新功能以保持最高分數列表處於最新狀態。這裏的優點是你只需要遍歷三個元素的列表。我修改了原來的代碼演示如何這可能工作:

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

#define SIZE 6 
#define MAX 3 

typedef struct { 
    double score; 
    int player_num; 
} player_t; 

void update_topscores(player_t **top, player_t *pplayer); 

int 
main(int argc, char *argv[]) { 
    int i; 

    int player_numbers[] = {1, 2, 3, 4, 5, 6}; 
    double scores[] = {0.765, 0.454, 0.454, 0.345, 0.643, 0.532}; 

    player_t *players = malloc(SIZE * sizeof(player_t)); 
    player_t **topscores = calloc(3, sizeof(player_t *)); 

    for (i = 0; i < SIZE; i++) { 
     players[i].score = scores[i]; 
     players[i].player_num = player_numbers[i]; 
     update_topscores(topscores, &(players[i])); 
    } 

    for (i = 0; i < SIZE; i++) { 
     printf("Player %d: Score: %.3f\n", 
       players[i].player_num, players[i].score); 
    } 

    puts("Top Scores"); 
    for (i = 0; i < 3; i++) { 
     printf("Player %d: Score: %.3f\n", 
       topscores[i]->player_num, topscores[i]->score);  
    } 

    /* Change score for player 4 */ 
    players[3].score = 0.755; 
    update_topscores(topscores, &(players[3])); 
    puts("New Top Scores"); 
    for (i = 0; i < 3; i++) { 
     printf("Player %d: Score: %.3f\n", 
       topscores[i]->player_num, topscores[i]->score); 
    } 

    free(players); 
    free(topscores); 

    return 0; 
} 

void update_topscores(player_t **top, player_t *pplayer) 
{ 
    int i; 
    player_t *temp; 

    for (i = 0; i < 3; i++) 
     if (top[i] == NULL) { 
      top[i] = pplayer; 
      return ; 
     } 
    for (i = 0; i < 3; i++) { 
     if ((pplayer->score) > (top[i]->score)) { 
      temp = top[i]; 
      top[i] = pplayer; 
      update_topscores(top, temp); 
      break; 
     } 
    } 

    return ; 
} 

你可以看到,有一個功能update_topscores()用來更新列表。在上面的代碼中,這是在構建初始玩家列表時使用的。然後,當播放器4的得分被更新時,該功能被再次調用,導致新的最高得分列表。該列表沒有排序,但如果需要的話,這樣做很容易,而且您只需對三個條目列表進行排序。

還有一個額外的分配給玩家指針的三個指針,topscores,這當然必須在最後釋放。

下面是一個示例輸出:

Player 1: Score: 0.765 
Player 2: Score: 0.454 
Player 3: Score: 0.454 
Player 4: Score: 0.345 
Player 5: Score: 0.643 
Player 6: Score: 0.532 
Top Scores 
Player 1: Score: 0.765 
Player 5: Score: 0.643 
Player 6: Score: 0.532 
New Top Scores 
Player 1: Score: 0.765 
Player 4: Score: 0.755 
Player 5: Score: 0.643