高效排序结构数组

时间:2016-10-16 17:03:43

标签: c arrays sorting struct

我正在使用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 个答案:

答案 0 :(得分: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 :(得分: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;
}

答案 2 :(得分: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