2016-10-16 7 views
2

qsortを使用して構造体の配列をソートしていますが、配列を部分的にソートすることで上位3つの最高点を抽出する効率的な方法を探しています。私の構造は次のようになります。構造体の配列を効率的にソート

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

と私はこのような構造体の配列をmallocされている:

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

私は構造体のこの配列をソート方法は、最初にスコアをソートすることであり、そして得点場合次に、選手の番号でソートします。

私のコードはqsortで次のようになります。私はこれを行うには別の方法を探していますが、より効率的な方法は、それぞれのプレイヤー番号とともに、トップ3のスコアを抽出するために

#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だから、冗長かもしれない3つの比較を最適化する価値はありません。コードをシンプルに保つ。そして、プログラムのこの部分がはるかに遅いということを後で判断した場合は、それを最適化する必要があります。 –

答えて

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であるため、私はそれを考慮しました。

プログラムは、データの1回のパスと各レコードの最上位の1回のパスを行います。固定配列を使用していますが、ニーズに合わせる必要があります。

#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

ここでは、それらへのポインタを格納することにより、上位3つのスコアを追跡するソリューションです。プレーヤーを追加したりスコアを変更すると、トップスコアリストを最新の状態に保つために更新機能が呼び出されます。ここでの利点は、3つの要素のリストを反復処理する必要があることだけです。私は、これはうまくいくかもしれない方法を示すためにあなたの元のコードを変更:

#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のスコアが更新されると、関数が再び呼び出され、新しいトップスコアのリストが得られます。リストはソートされませんが、必要に応じて簡単に行うことができ、3つのエントリのリストをソートするだけです。

プレイヤーポインターへのポインタが3つ追加されました。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