如何用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
相关产品推荐
相关产品推荐

