c语言统计单词个数的方法

1. 简介

在计算机编程领域中,统计单词个数是一个很基础的需求,常见于文本处理、搜索引擎等领域。本文将介绍如何使用C语言统计单词个数的方法,具体包括如何定义单词、如何读取文本、如何统计单词等。

2. 定义单词

在统计单词之前,需要先定义单词的概念。一般来说,单词是由字母组成的,包括大小写字母、数字、下划线等。但是,还需要考虑一些特殊情况:

单词中可能包含连字符“-”,例如“check-in”

单词中可能包含撇号“'”,例如“don't”

单词中可能存在缩写,例如“Mr.”、“U.S.”

基于以上考虑,我们可以将单词定义为满足以下条件的字符串:

由大小写字母、数字、下划线、连字符、撇号组成

长度不为0

连字符或撇号不能在单词的开头或结尾

缩写中只能包含大小写字母和点号,点号不能在开头或结尾

3. 读取文本

在进行单词统计之前,需要先读取待统计的文本。对于较小的文本,可以一次性读入内存,然后逐个单词进行统计;对于比较大的文本,需要分块读取,以避免内存不足的问题。

下面是一个读取文本的例子,可以读取整个文件并按单词进行划分:

#include <stdio.h>

#include <ctype.h>

#define MAX_WORD_LEN 100

int getword(char *word, int max_len)

{

int c, len = 0;

while ((c = getchar()) != EOF && !isalnum(c) && c != '-' && c != '\'');

if (c == EOF) return EOF;

do {

if (len < max_len - 1) word[len++] = tolower(c);

else break;

} while ((c = getchar()) != EOF && (isalnum(c) || c == '-' || c == '\'' || c == '.'));

word[len] = '\0';

return len;

}

void process_file(void)

{

char word[MAX_WORD_LEN];

int count = 0;

while (getword(word, MAX_WORD_LEN) != EOF) {

printf("%s\n", word);

count++;

}

printf("Total words: %d\n", count);

}

int main(void)

{

process_file();

return 0;

}

上述代码中定义了一个函数getword,它会读取一个单词并将其转换为小写字母,然后返回单词的长度。如果读取到文件末尾,函数返回EOF。在process_file函数中,逐个读取单词并打印出来,最后输出总单词数。

3.1 getword函数详解

getword函数中使用了一些C语言的库函数,这里进行详细解释:

getchar():从标准输入流中读取一个字符,返回其ASCII码值。

isalnum(c):判断字符c是否为字母或数字,如果是返回非零值,否则返回0。

tolower(c):将字符c转换为小写字母并返回其ASCII码值。

在getword函数中,首先调用getchar()读取一个字符,如果遇到非字母数字或连字符或撇号,就继续读取下一个字符,直到遇到一个字母数字或连字符或撇号为止。然后,从该字符开始,逐一读取后面的字符,直到遇到非字母数字或连字符或撇号或点号为止,同时将读取到的字符转换为小写字母,并存储到word数组中。当读取的字符数量达到max_len-1时,函数结束。

3.2 分块读取

当待读取的文件较大时,为避免内存不足的问题,可以采用分块读取的方式。具体地,每次读取固定长度的文本块,然后对每个文本块进行单词统计,最后将各个文本块的单词数累加起来。

下面是一个示例代码,每次读取文本块的长度为BLOCK_SIZE

#define BLOCK_SIZE 1024

void process_file(void)

{

char word[MAX_WORD_LEN];

int count = 0;

char buf[BLOCK_SIZE];

size_t n;

FILE *fp = fopen("file.txt", "r");

if (fp == NULL) {

perror("Error opening file");

return;

}

while ((n = fread(buf, 1, BLOCK_SIZE, fp)) > 0) {

const char *p = buf;

const char *end = buf + n;

while (p < end) {

const char *q = p;

while (q < end && isalnum(*q)) q++;

if (q > p) {

strncpy(word, p, q - p);

word[q - p] = '\0';

printf("%s\n", word);

count++;

}

p = q + 1;

}

}

fclose(fp);

printf("Total words: %d\n", count);

}

在该示例代码中,首先打开文件并检查是否成功打开,然后分块读取文件,每次读取的文本块大小为BLOCK_SIZE。在每个文本块中,逐个读取单词并进行统计,最终输出总单词数。

4. 统计单词

读取文件并将单词进行划分后,可以统计单词的数量了。具体地,可以使用哈希表等数据结构来存储单词及其出现次数。每次读取一个单词后,在哈希表中查找该单词,如果已存在,则将其出现次数加1;否则,将该单词加入哈希表并设置其出现次数为1。

下面是一个基于哈希表实现的单词统计代码:

#include <stdio.h>

#include <stdlib.h>

#include <ctype.h>

#include <string.h>

#define MAX_WORD_LEN 100

#define HASH_TABLE_SIZE 10000

typedef struct hash_node {

char *key;

int value;

struct hash_node *next;

} hash_node_t;

hash_node_t **hash_table = NULL;

unsigned int hash(const char *key)

{

unsigned int hash_val = 0;

while (*key) {

hash_val = (hash_val << 4) + *key;

key++;

}

return hash_val;

}

void init_hash_table(void)

{

int i;

hash_table = (hash_node_t **)malloc(sizeof(hash_node_t*) * HASH_TABLE_SIZE);

for (i = 0; i < HASH_TABLE_SIZE; i++) {

hash_table[i] = NULL;

}

}

hash_node_t* lookup(const char *key)

{

hash_node_t *node;

unsigned int hash_val = hash(key) % HASH_TABLE_SIZE;

for (node = hash_table[hash_val]; node != NULL; node = node->next) {

if (strcmp(key, node->key) == 0) {

return node;

}

}

return NULL;

}

void insert(const char *key, int value)

{

hash_node_t *node;

unsigned int hash_val = hash(key) % HASH_TABLE_SIZE;

node = (hash_node_t*)malloc(sizeof(hash_node_t));

node->key = (char*)malloc(strlen(key) + 1);

strcpy(node->key, key);

node->value = value;

node->next = hash_table[hash_val];

hash_table[hash_val] = node;

}

void process_file(void)

{

char word[MAX_WORD_LEN];

int count = 0;

while (getword(word, MAX_WORD_LEN) != EOF) {

if (!lookup(word)) {

insert(word, 1);

} else {

lookup(word)->value++;

}

count++;

}

printf("Total words: %d\n", count);

}

void print_hash_table(void)

{

int i;

for (i = 0; i < HASH_TABLE_SIZE; i++) {

hash_node_t *node;

for (node = hash_table[i]; node != NULL; node = node->next) {

printf("%s : %d\n", node->key, node->value);

}

}

}

int main(void)

{

init_hash_table();

process_file();

print_hash_table();

return 0;

}

在上述代码中,定义了一个哈希表结构体hash_node_t,其包含单词、出现次数和下一个节点的指针。定义一个全局变量hash_table来存储哈希表。使用init_hash_table函数来初始化哈希表,将所有指针置空。使用hash函数将单词转换为哈希值。使用lookup函数在哈希表中查找单词,如果找到则返回其节点,否则返回NULL。使用insert函数将单词插入哈希表中。在process_file函数中,读取每个单词并统计其出现次数,如果单词已经在哈希表中,则将其出现次数加1;否则,将其插入哈希表并设置初始计数为1。在print_hash_table函数中,将哈希表中的所有单词及其出现次数打印出来。

4.1 哈希冲突

在哈希表中,不同的单词可能映射到同一个哈希值,这种情况称为哈希冲突。一个常用的解决方法是将哈希表中的每个位置都设为一个链表,同一个哈希值的元素都存储在链表中。当查找或插入元素时,先找到对应的表头,然后在链表中查找。

4.2 提高单词匹配的效率

对于较长的单词列表,哈希表的查找和插入操作是非常耗时的,可以通过以下两种方式来提高其效率:

使用平衡树等高效的数据结构代替哈希表。

引入一些启发式算法,构建前缀树等数据结构,以减少查找或插入次数。

5. 总结

通过以上介绍,我们了解到了如何使用C语言统计单词个数的方法,包括如何定义单词、如何读取文本、如何统计单词等。同时,我们也可以从中了解到哈希表以及哈希冲突解决方法。希望本文能够对希望学习或使用C语言进行单词统计的读者有所帮助。

后端开发标签