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

如何对存储姓名的二维字符串数组排序以展示出现次数Top5?

如何在禁用<string.h>时,按姓名出现次数降序排序二维字符串数组并输出TOP5

我的需求是对存储姓名的二维字符串数组,按姓名出现次数从多到少排序,最终输出格式如下:

TOP 5 PLAYERS
1. GEORGE - WINS: X
2. HENRY - WINS: X
3. JOHN - WINS: X
4. MARRY - WINS: X
5. JULIA - WINS: X

其中X是姓名在数组中的出现次数。

限制条件:不能使用<string.h>库,仅允许调用<stdio.h>中的函数。

目前我已经实现了从scores.txt读取姓名存入二维数组并展示的功能,但缺少排序和统计逻辑,当前只能输出文件中读取的前5个原始姓名,现有代码如下:

#include <stdio.h>

#define MAX_USERNAME_CHARS 20 // 假设MAX_USERNAME_CHARS是已定义的宏

void leaderboard(FILE *scores) {
    
    int totalNames = 4;
    int row; // 注意:这里未初始化,会导致未定义行为
    char tempName[MAX_USERNAME_CHARS-1];
    char namesArray[500][MAX_USERNAME_CHARS-1];
    
    scores = fopen("scores.txt","r");
    
        while (fscanf(scores,"%s",tempName) == 1) {
            int strlength;
            for (strlength = 0; tempName[strlength] != '\0';strlength++);
            
            for (int i=0; i <= strlength; i++) {
                namesArray[row][i] = tempName[i];
            }
            row++;
        }
    
    //Insert Sorting Code Here
    
    printf("\nTOP 5 PLAYERS\n");
    for (int i=0;i<=totalNames;i++) {
        printf("%d. ",i+1);
        for (int j=0;j<=MAX_USERNAME_CHARS-2;j++) {
            printf("%c",namesArray[i][j]);
        }
        printf(" - WINS: X\n");
    }
}

现在需要补充统计和排序的逻辑,完成需求。


解决方案

要完成需求,需要分三步:统计每个姓名的出现次数、按次数降序排序、输出TOP5,以下是完整实现:

1. 自定义字符串工具函数(替代<string.h>接口)

因为不能用<string.h>,自己实现字符串相等判断和复制功能:

// 判断两个字符串是否相等,相等返回1,不等返回0
int strEquals(const char *a, const char *b) {
    int i = 0;
    while (a[i] != '\0' && b[i] != '\0') {
        if (a[i] != b[i]) {
            return 0;
        }
        i++;
    }
    // 两个字符串同时结束才算相等
    return (a[i] == '\0' && b[i] == '\0');
}

// 复制字符串到目标地址(替代strcpy)
void strCopy(char *dest, const char *src) {
    int i = 0;
    while (src[i] != '\0') {
        dest[i] = src[i];
        i++;
    }
    dest[i] = '\0'; // 手动添加字符串结束符
}

2. 定义结构体存储姓名与次数

用结构体关联姓名和对应的出现次数,方便后续排序操作:

typedef struct {
    char name[MAX_USERNAME_CHARS-1];
    int count;
} PlayerStats;

3. 完整修改后的leaderboard函数

#include <stdio.h>

#define MAX_USERNAME_CHARS 20

typedef struct {
    char name[MAX_USERNAME_CHARS-1];
    int count;
} PlayerStats;

// 自定义字符串相等判断函数
int strEquals(const char *a, const char *b) {
    int i = 0;
    while (a[i] != '\0' && b[i] != '\0') {
        if (a[i] != b[i]) {
            return 0;
        }
        i++;
    }
    return (a[i] == '\0' && b[i] == '\0');
}

// 自定义字符串复制函数
void strCopy(char *dest, const char *src) {
    int i = 0;
    while (src[i] != '\0') {
        dest[i] = src[i];
        i++;
    }
    dest[i] = '\0';
}

void leaderboard(FILE *scores) {
    int row = 0; // 初始化row,修复原代码的未定义行为
    char tempName[MAX_USERNAME_CHARS-1];
    char namesArray[500][MAX_USERNAME_CHARS-1];
    PlayerStats stats[500];
    int statsCount = 0;

    scores = fopen("scores.txt", "r");
    if (!scores) { // 添加文件打开失败的判断
        printf("Failed to open scores.txt\n");
        return;
    }

    // 读取所有姓名到二维数组
    while (fscanf(scores, "%s", tempName) == 1) {
        int strlength = 0;
        while (tempName[strlength] != '\0') strlength++;
        
        for (int i = 0; i <= strlength; i++) {
            namesArray[row][i] = tempName[i];
        }
        row++;
    }
    fclose(scores); // 读取完成后关闭文件

    // 统计每个姓名的出现次数
    for (int i = 0; i < row; i++) {
        int found = 0;
        // 检查当前姓名是否已经统计过
        for (int j = 0; j < statsCount; j++) {
            if (strEquals(namesArray[i], stats[j].name)) {
                stats[j].count++;
                found = 1;
                break;
            }
        }
        // 如果没统计过,添加到stats数组
        if (!found) {
            strCopy(stats[statsCount].name, namesArray[i]);
            stats[statsCount].count = 1;
            statsCount++;
        }
    }

    // 按出现次数降序排序(冒泡排序,适合小规模数据)
    for (int i = 0; i < statsCount - 1; i++) {
        for (int j = 0; j < statsCount - 1 - i; j++) {
            if (stats[j].count < stats[j+1].count) {
                // 交换两个PlayerStats元素
                PlayerStats temp = stats[j];
                stats[j] = stats[j+1];
                stats[j+1] = temp;
            }
        }
    }

    // 输出TOP5玩家
    printf("\nTOP 5 PLAYERS\n");
    int topCount = (statsCount < 5) ? statsCount : 5;
    for (int i = 0; i < topCount; i++) {
        printf("%d. %s - WINS: %d\n", i+1, stats[i].name, stats[i].count);
    }
}

关键修改点说明

  • 修复了原代码中row未初始化的问题,避免未定义行为
  • 添加了文件打开失败的判断,增强代码鲁棒性
  • 实现了自定义的字符串比较和复制函数,完全避开<string.h>
  • 使用结构体存储姓名和次数,完成去重统计
  • 用冒泡排序实现按次数降序排序(数据量小,冒泡排序足够高效)
  • 处理了总玩家数不足5的情况,避免数组越界

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 23:40:38