You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用C语言按玩家分组统计得分总和?

C语言实现玩家得分分组求和及R/pandas底层实现解析

现有如下格式的文本文件,左列为玩家姓名,右列为游戏得分:

john 40
mary 50
john 30
kevin 88
kevin 29
joe 102
david 11
mary 134

需要按玩家分组求和,输出格式如下:

john 70
mary 184
kevin 117
joe 102
david 11

已知用R或Python/pandas可轻松实现,但希望用C语言完成。尝试用全局结构体数组存储数据时遇到读取和存储的问题,求高效实现方式;另外想了解R和pandas基于C的底层实现逻辑。

C语言高效实现方案

高效实现的核心是用哈希表存储玩家姓名与累计得分的映射,避免数组遍历查找的O(n)开销,哈希表的插入、查找平均复杂度为O(1)。

方案1:使用GLib的GHashTable(成熟高效)

GLib提供了现成的哈希表实现,无需手动造轮子:

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

// 哈希表键值对销毁函数,释放内存
void free_key_value(gpointer key, gpointer value, gpointer user_data) {
    free(key);
    free(value);
}

int main() {
    FILE *fp = fopen("scores.txt", "r");
    if (!fp) {
        perror("Failed to open file");
        return 1;
    }

    // 创建哈希表:键为字符串,值为存储得分的int指针
    GHashTable *score_table = g_hash_table_new_full(g_str_hash, g_str_equal, free_key_value, NULL);

    char name[256];
    int score;
    // 逐行读取文件内容
    while (fscanf(fp, "%s %d", name, &score) == 2) {
        int *existing_score = g_hash_table_lookup(score_table, name);
        if (existing_score) {
            // 玩家已存在,累加得分
            *existing_score += score;
        } else {
            // 玩家不存在,创建新条目
            char *name_copy = strdup(name);
            int *new_score = malloc(sizeof(int));
            *new_score = score;
            g_hash_table_insert(score_table, name_copy, new_score);
        }
    }

    fclose(fp);

    // 遍历哈希表输出结果
    GHashTableIter iter;
    gpointer key, value;
    g_hash_table_iter_init(&iter, score_table);
    while (g_hash_table_iter_next(&iter, &key, &value)) {
        printf("%s %d\n", (char*)key, *(int*)value);
    }

    // 销毁哈希表释放内存
    g_hash_table_destroy(score_table);
    return 0;
}

编译时需链接GLib库:gcc -o score_sum score_sum.c $(pkg-config --cflags --libs glib-2.0)

方案2:手动实现简单哈希表(无第三方依赖)

如果不想依赖外部库,可自行实现基于数组+链表解决冲突的哈希表:

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

// 链表节点结构体:存储玩家姓名、得分及下一个节点指针
typedef struct Node {
    char *name;
    int score;
    struct Node *next;
} Node;

// 哈希表结构体:存储桶数组及桶数量
typedef struct HashTable {
    Node **buckets;
    int size;
} HashTable;

// 字符串哈希函数
unsigned int hash(const char *str, int size) {
    unsigned int hash = 0;
    while (*str) {
        hash = hash * 31 + *str++;
    }
    return hash % size;
}

// 创建指定大小的哈希表
HashTable* create_hash_table(int size) {
    HashTable *table = malloc(sizeof(HashTable));
    table->size = size;
    table->buckets = calloc(size, sizeof(Node*));
    return table;
}

// 更新玩家得分:存在则累加,不存在则新增
void update_score(HashTable *table, const char *name, int score) {
    unsigned int idx = hash(name, table->size);
    Node *current = table->buckets[idx];

    // 查找现有玩家
    while (current) {
        if (strcmp(current->name, name) == 0) {
            current->score += score;
            return;
        }
        current = current->next;
    }

    // 新增玩家节点
    Node *new_node = malloc(sizeof(Node));
    new_node->name = strdup(name);
    new_node->score = score;
    new_node->next = table->buckets[idx];
    table->buckets[idx] = new_node;
}

// 遍历输出哈希表内容
void print_hash_table(HashTable *table) {
    for (int i = 0; i < table->size; i++) {
        Node *current = table->buckets[i];
        while (current) {
            printf("%s %d\n", current->name, current->score);
            current = current->next;
        }
    }
}

// 销毁哈希表释放所有内存
void destroy_hash_table(HashTable *table) {
    for (int i = 0; i < table->size; i++) {
        Node *current = table->buckets[i];
        while (current) {
            Node *temp = current;
            current = current->next;
            free(temp->name);
            free(temp);
        }
    }
    free(table->buckets);
    free(table);
}

int main() {
    FILE *fp = fopen("scores.txt", "r");
    if (!fp) {
        perror("Failed to open file");
        return 1;
    }

    // 创建大小为64的哈希表(可根据数据量调整)
    HashTable *table = create_hash_table(64);

    char name[256];
    int score;
    while (fscanf(fp, "%s %d", name, &score) == 2) {
        update_score(table, name, score);
    }

    fclose(fp);
    print_hash_table(table);
    destroy_hash_table(table);

    return 0;
}

编译指令:gcc -o score_sum score_sum.c

R和pandas的底层实现逻辑

R的底层实现

R的核心解释器基于C编写,高性能分组操作(如dplyr::group_by、data.table的分组)均由C实现:

  • 先将字符串类型的分组键(如玩家姓名)通过哈希表映射为整数ID,后续分组仅需比较整数,规避字符串比较的性能开销。
  • 分组求和时,直接在C层遍历数据,根据整数ID累加对应组的数值,全程避免R解释器的循环开销;data.table更是直接在C层处理数据,无需在R与C之间频繁拷贝数据,效率极高。

pandas的底层实现

pandas的核心逻辑多通过Cython(可编译为C的类Python语言)实现,分组操作流程:

  • 先对分组列进行编码:用哈希表为每个唯一字符串分配整数ID,生成整数数组(codes数组)。
  • 基于codes数组对数值列分组累加:底层用C级循环遍历数组,根据codes值将得分累加到对应组,全程避开Python全局解释器锁(GIL),性能接近纯C;同时利用连续内存块的优势减少缓存失效,进一步提升效率。

内容的提问来源于stack exchange,提问作者user9026

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 08:50:27