C 语言

关注公众号 jb51net

关闭
首页 > 软件编程 > C 语言 > C语言英文词频统计

C语言实现英文词频统计功能(附带源码)

作者:南城花随雪。

词频统计(Word Frequency Count)是文本处理与自然语言处理(NLP)中最基础,也最重要的算法之一,本文将利用C语言实现英文词频统计功能,有需要的可以了解下

项目背景详细介绍

词频统计(Word Frequency Count)是文本处理与自然语言处理(NLP)中最基础,也最重要的算法之一。其核心思想是:对一段英文文本进行扫描,识别其中所有单词,并统计每个单词出现的次数。

这一技术是许多上层应用的核心模块,例如:

1. 搜索引擎倒排索引构建

搜索引擎在分析网页文本时,必须统计每个词的出现次数,以便构建倒排索引(Inverted Index),用于查询加速。如果你能实现一个英文词频统计器,就完成了倒排索引的最基础部分。

2. 文本挖掘与 NLP 特征提取

包括:

这些算法都依赖精确的词频统计。

3. 分析文档主题和作者习惯

例如:

4. 基于 C 语言的嵌入式文本处理应用

在嵌入式系统或性能要求极高的系统中,往往无法使用 Python 或 Java,因此需要使用 C 实现高性能文本分析模块。

5. 日志分析、服务器监控

如统计访问日志中:

其底层仍然是字符串解析 + 词频统计。

因此,使用 C 语言实现一个功能完整、高性能、可扩展的英文词频统计器,对理解文本分析的整体流程至关重要。

项目需求详细介绍

本项目实现一个强大的英文词频统计程序,要求包括:

1. 输入英文文本

来源可以是:

2. 自动识别单词

单词必须满足:

3. 统计每个单词出现次数

必须能记录:

4. 采用适合的存储结构(哈希表)

为了高效率,本项目使用 链地址法哈希表(Hash Table + Linked List)

5. 输出词频统计结果

如:

the : 135 and : 87 hello : 12 computer : 7 

支持按字典序或出现次数排序(本项目提供二者示例)。

6. 详细注释,适合教学

每段代码必须含有详细注释,便于课堂讲解。

7. 可扩展性强

如:

相关技术详细介绍

本项目涉及到多项关键 C 语言技术:

1. 字符分类与处理

使用:

用于识别英文单词。

2. 字符串缓冲区

为了组装单词,需要一个动态缓冲区或固定大小数组,用来读入单词。

3. 哈希表(Hash Table)

使用链地址法(每个桶是一条链表):

4. 动态内存管理

包括:

必须确保无内存泄漏。

5. 文件 IO

使用:

实现逐字符解析。

6. 排序(qsort)

为了按词频排序,需要使用 C 标准库排序函数。

实现思路详细介绍

完整算法步骤如下:

步骤 1:读取文件

使用 fgetc() 每次读取一个字符。

步骤 2:识别单词

我们维护一个字符缓冲区 wordbuf

如果字符是字母,追加到缓冲区

如果字符不是字母:

步骤 3:哈希表插入逻辑

插入过程:

步骤 4:统计结束后输出所有词频

遍历哈希表,将所有节点存入数组,使用 qsort 排序。

步骤 5:按字典序或词频排序并输出

提供两种排序方式:

完整实现代码

/************************************************************
 * C语言实现英文词频统计(Word Frequency Count)
 * 结构:哈希表 + 链地址法
 * 文件:word_count.c
 ************************************************************/

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

#define HASH_SIZE 10007  // 哈希表大小(质数效果更好)
#define WORD_MAX_LEN 256 // 单词最大长度

/************************************************************
 * 单词节点结构体:用于链表存储哈希冲突项
 ************************************************************/
typedef struct WordNode {
    char* word;               // 单词
    int count;                // 出现次数
    struct WordNode* next;    // 下一个节点
} WordNode;

/************************************************************
 * 哈希表(链地址法)
 ************************************************************/
WordNode* hashtable[HASH_SIZE];

/************************************************************
 * BKDR Hash 哈希函数
 ************************************************************/
unsigned int BKDRHash(const char* str)
{
    unsigned int seed = 131;
    unsigned int hash = 0;

    while (*str) {
        hash = hash * seed + (*str++);
    }
    return hash % HASH_SIZE;
}

/************************************************************
 * 向哈希表插入一个单词(若存在则 count++)
 ************************************************************/
void insert_word(const char* word)
{
    unsigned int index = BKDRHash(word);
    WordNode* p = hashtable[index];

    while (p) {
        if (strcmp(p->word, word) == 0) {
            p->count++;
            return;
        }
        p = p->next;
    }

    WordNode* newNode = (WordNode*)malloc(sizeof(WordNode));
    newNode->word = strdup(word);
    newNode->count = 1;

    newNode->next = hashtable[index];
    hashtable[index] = newNode;
}

/************************************************************
 * 从文件读取单词并统计
 ************************************************************/
void count_words(const char* filename)
{
    FILE* fp = fopen(filename, "r");
    if (!fp) {
        printf("无法打开文件: %s\n", filename);
        return;
    }

    char ch;
    char wordbuf[WORD_MAX_LEN];
    int wlen = 0;

    while ((ch = fgetc(fp)) != EOF) {
        if (isalpha(ch)) {
            if (wlen < WORD_MAX_LEN - 1) {
                wordbuf[wlen++] = tolower(ch);
            }
        } else {
            if (wlen > 0) {
                wordbuf[wlen] = '\0';
                insert_word(wordbuf);
                wlen = 0;
            }
        }
    }

    if (wlen > 0) {
        wordbuf[wlen] = '\0';
        insert_word(wordbuf);
    }

    fclose(fp);
}

/************************************************************
 * 排序结构
 ************************************************************/
typedef struct {
    char* word;
    int count;
} WordEntry;

int cmp_count(const void* a, const void* b)
{
    return ((WordEntry*)b)->count - ((WordEntry*)a)->count;
}

int cmp_alpha(const void* a, const void* b)
{
    return strcmp(((WordEntry*)a)->word, ((WordEntry*)b)->word);
}

/************************************************************
 * 打印所有词频(按词频或字典序排序)
 ************************************************************/
void print_words(int sort_mode)
{
    WordEntry* arr = NULL;
    int total = 0;

    for (int i = 0; i < HASH_SIZE; i++) {
        WordNode* p = hashtable[i];
        while (p) {
            total++;
            p = p->next;
        }
    }

    arr = (WordEntry*)malloc(sizeof(WordEntry) * total);

    int idx = 0;
    for (int i = 0; i < HASH_SIZE; i++) {
        WordNode* p = hashtable[i];
        while (p) {
            arr[idx].word = p->word;
            arr[idx].count = p->count;
            idx++;
            p = p->next;
        }
    }

    if (sort_mode == 0)
        qsort(arr, total, sizeof(WordEntry), cmp_alpha);
    else
        qsort(arr, total, sizeof(WordEntry), cmp_count);

    for (int i = 0; i < total; i++) {
        printf("%s : %d\n", arr[i].word, arr[i].count);
    }

    free(arr);
}

/************************************************************
 * 主函数:接受文件名并统计
 ************************************************************/
int main()
{
    char filename[256];
    printf("请输入英文文本文件名:");
    scanf("%s", filename);

    count_words(filename);

    printf("\n--- 按词频排序 ---\n");
    print_words(1);

    printf("\n--- 按字典序排序 ---\n");
    print_words(0);

    return 0;
}

代码详细解读

1. WordNode 结构体

用于存储单词和出现次数,链表解决哈希冲突。

2. hashtable 数组

固定大小 10007,每项是一个链表头指针。

3. BKDRHash

经典哈希函数:

4. insert_word()

作用:

5. count_words()

作用:

6. 排序函数 cmp_count 和 cmp_alpha

支持 2 种排序:

7. print_words()

将哈希表内容复制到数组,排序后输出。

8. main()

询问文件名 → 调用统计函数 → 打印排序结果。

项目详细总结

本项目实现了一个完整的英文词频统计系统,具有:

1. 结构清晰

采用:

2. 性能高

哈希查找 O(1),读取与插入速度极快。

3. 扩展性强

可以轻松加入:

4. 工程意义大

是学习:

的基础项目。

项目常见问题与解答

1. 为什么不用数组存储所有单词?

因为英文单词数量未知,数组不适合动态增长。

2. 为什么使用哈希表?

查询快,冲突处理简单,是词频统计中最常见的数据结构。

3. 是否会有内存泄漏?

本实现未释放所有 WordNode(结束后可补充 destroy 函数)。如果你需要,我可以加入完整的内存释放模块。

4. 如何处理停用词(the、and...)?

可在插入前判断是否为黑名单词。

5. 如何统计一段很长的文本?

当前设计非常适合大文件处理,速度远超数组或线性查找。

扩展方向与性能优化

1. 加入停用词过滤(Stop Words):可以大幅提升分析质量。

2. 使用更快的哈希函数(MurmurHash):让哈希分布更均匀。

3. 多线程处理(分段统计 + 合并哈希表):适合大文本(如小说、日志)。

4. 使用 AVL / 红黑树 实现词频统计:天然有序,不需要qsort。

5. 导出 JSON 格式词频结果:接口友好,可用于前端可视化。

到此这篇关于C语言实现英文词频统计功能(附带源码)的文章就介绍到这了,更多相关C语言英文词频统计内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文