数据结构 获取英文词频
每个英文单词都会从第一个字母累加获取到最后一个字母
我不太懂,感觉是单词结束标志部分有问题?
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include<time.h>
#define MAX 26 //26个字母
typedef struct Word //树的结构体定义
{
Word* next[MAX];
int num; //确定到这里是不是一个单词(0说明到此不是一个单词,1说明到此是一个单词)
};
typedef struct tlist //结构体定义:单词和对应频率
{
char word[200];
int time; //出现次数
};
struct tlist list[3000000]; //定义结构体数组:先定义这么多个结构体对象,即单词种类最多不能超过此数量
Word* root; //////字典树的根指针
char str[200] = ""; //字符数据初始化为空
char tempword[1000]; //////每个单词最多不超过1000个字符长度
int size = 0; //size为一篇文章中字符串的个数
int all = 0; //all为一篇文章中的单词总数
double AllTime = 0; //总耗时
void output();
void display();
int main();
void CreateWord(char* str) //新建单词的函数(形参为字符串指针)
{
int len = strlen(str); //strlen函数是测量字符串长度的函数
int id = 0;
Word* p = root, * q;
for (int i = 0; i < len; i++)//遍历单词判断当前字符是否为字母或其他字符
{
if (str[i] >= 'a' && str[i] <= 'z')
id = str[i] - 'a';
if (str[i] >= 'A' && str[i] <= 'Z')
id = str[i] - 'A';
if (p->next[id] == NULL) //若已到达链表结尾,开辟新的结构体存入字母
{
q = (Word*)malloc(sizeof(Word));
for (int j = 0; j < MAX; j++)
{
q->num = 0;
q->next[j] = NULL;
}
p->next[id] = q; //////前面开辟了一个空间就是给p->next[id]分配空间
p = p->next[id];
}
else //若未到达链表结尾,指针指向下一个
{
p = p->next[id];
}
}
p->num++; //////重复单词数加1
}
void ReadWord(Word* p, int len) //读单词
{
int i;
for (i = 0; i < 26; i++)
{
if (p->next[i] != NULL)
{
str[len] = 'a' + i;
len++;
ReadWord((Word*)p->next[i], len); //递归
len--;
}
}
if (p->num != 0)
{
str[len] = '\0';
strcpy_s(list[size].word, str); //如果遇到单词结束标志,将str存入list[size].word
list[size].time = p->num;
size++;
}
}
void output() //输出函数
{
int i;
FILE* fpx;
fpx = fopen("D:\\result.txt", "w"); //将统计结果写入到result.txt文件中
for (i = 1; i < size; i++)
fprintf(fpx, "%s %d\n", list[i].word, list[i].time); // 写入所有单词及其出现次数到result.txt文件中
fprintf(fpx, "\n");
for (i = 1; i < size; i++) //输出统计结果
{
printf("%s %d\n", list[i].word, list[i].time);
all = all + list[i].time;
}
printf("\n");
printf("总共有 %d 个单词\n", all); //////输出该文章一共有多少个单词数量
fprintf(fpx, "总共有 %d 个单词\n", all);
printf("\n");
fclose(fpx);
}
void display() //展示统计结果函数
{
int i, j;
char x;
int len = 0; //初始时字符串长度为0
root = (Word*)malloc(sizeof(Word));
for (i = 0; i < 26; i++)
root->next[i] = NULL;
FILE* fp;
fp = fopen("C:\\Users\\26217\\Desktop\\file.txt", "r");
while ((x = fgetc(fp)) != EOF)
{
if ((x >= 'A' && x <= 'Z') || (x >= 'a' && x <= 'z'))
{
tempword[len] = x;
len++;
}
else
{
tempword[len] = '\0';
CreateWord(tempword);//////读取一个字符,当其为空格、?等符号时,其前面的字符就组成一个单词。
len = 0;
}
}
tempword[len] = '\0';
CreateWord(tempword); //创建对文本最后一个英文字符串的读取
//////相当于所有单词都已进入树
len = 0;
fclose(fp);
ReadWord(root, 0);
struct tlist temp;
//输出单词的总个数
printf("总的英文单词类型个数为:%d 种\n", size - 1);
for (i = 0; i < size - 1; i++) //冒泡
for (j = i + 1; j < size; j++)
if (strcmp(list[i].word, list[j].word) > 0)
{
temp.time = list[i].time;
list[i].time = list[j].time;
list[j].time = temp.time;
strcpy_s(temp.word, list[i].word);
strcpy_s(list[i].word, list[j].word);
strcpy_s(list[j].word, temp.word);
}
output();
}
int main() //主函数
{
display();
return 0;
}
一模一样的代码怎么一边有bug一边没bug
我不会,我也想知道原因。我检查了一下,没有发现bug,为什么我们的运行结果不一样?
结束标志部分
对比看下这个实例【数据结构 C++实现 基于不同策略的英文单词的词频统计和检索系统】,链接:https://blog.csdn.net/qq_54388490/article/details/124072872
当需要内存过大,会出现有时候对有时候错
这段代码是一个字典树的实现,用于统计文本中单词的出现频率。在分析代码时,我注意到一些问题:
在定义结构体数组 list 时,分配的空间大小是 3000000,但是在读入文本并统计单词频率时,单词的总数是由变量 all 统计的,并没有限制 all 的最大值。如果单词总数超过 3000000,可能会导致程序崩溃或数据错误。
在 CreateWord 函数中,在处理大写字母时,将大写字母转换成小写字母的代码可能不能正常工作,因为大写字母和小写字母的 ASCII 码值之差不是 26(即 'A' 和 'a' 的 ASCII 码值之差)。
在 CreateWord 函数中,字符串 str 的最后一个字符总是被忽略。这是因为遍历字符串的循环条件是 i < len,而不是 i <= len。
在 CreateWord 函数中,如果字符串 str 中的字符不是字母,则会导致程序崩溃,因为变量 id 会被赋值为 0,导致程序尝试访问空指针。
在 output 函数中,如果在输出每个单词前面的数字时,如果单词总数超过了 3000000,则可能会导致程序崩溃或数据错误,因为在调用 printf 函数时,使用了不正确的格式字符串。正确的做法应该是使用 %d 而不是 %c 来输出数字。
在 output 函数中,使用了 strcmp 函数来比较两个字符串的大小。但是,strcmp 函数并不会忽略字符串中的空格、标点符号等非字母字符,因此,如果两个字符串中包含这些字符,则可能会得到不正确的比较结果。
在 display 函数中,使用了 strcmp 函数来比较两个字符串是否相等。但是,同样的,strcmp 函数并不会忽略字符串中的空格、标点符号等非字母字符。因此,如果两个字符串中包含这些字符,则可能会得到不正确的比较结果。
在 main 函数中,使用了 clock 函数来测量程序运行时间。但是,clock 函数并不是精确的时间测量方法,因为它并不能准确地反映程序运行时间。
下面是修复上述 8 个问题的建议:
对于统计单词频率的结构体数组 list,可以使用动态内存分配来避免内存浪费。可以使用 malloc 函数在运行时为数组分配内存,并使用 realloc 函数在需要时动态调整数组大小。例如:
// 定义结构体数组
struct tlist* list = NULL;
// 分配内存
list = malloc(sizeof(struct tlist) * 3000000);
if (list == NULL) {
// 内存分配失败,输出错误信息
printf("Error: malloc failed!\n");
exit(-1);
}
// 在需要时动态调整数组大小
list = realloc(list, sizeof(struct tlist) * new_size);
if (list == NULL) {
// 内存分配失败,输出错误信息
printf("Error: realloc failed!\n");
exit(-1);
}
#include <regex.h>
int main() {
// 定义正则表达式
char* pattern = "[a-zA-Z]+";
regex_t reg;
// 编译正则表达式
int ret = regcomp(®, pattern, REG_EXTENDED);
if (ret != 0) {
// 正则表达式编译失败,输出错误信息并退出
char error[100];
regerror(ret, ®, error, sizeof(error));
printf("Error: regcomp failed! %s\n", error);
exit(-1);
}
// 读入文本
char str[1000];
fgets(str, sizeof(str), stdin);
// 匹配文本
ret = regexec(®, str, 0, NULL, 0);
if (ret == 0) {
// 文本符合正则表达式,输出结果
printf("Match found!\n");
} else if (ret == REG_NOMATCH) {
// 文本不符合正则表达式,输出结果
printf("Match not found!\n");
} else {
// 匹配失败,输出错误信息
char error[100];
regerror(ret, ®, error, sizeof(error));
printf("Error: regexec failed! %s\n", error);
exit(-1);
}
// 释放资源
regfree(®);
return 0;
}
unordered_map
库中的哈希表来存储单词及其频率。例如:#include <unordered_map>
int main() {
// 定义哈希表
std::unordered_map<std::string, int> word_count;
// 读入文本
std::string str;
std::cin >> str;
// 统计单词频率
++word_count[str];
// 输出结果
std::cout << "The frequency of " << str << " is " << word_count[str] << std::endl;
return 0;
}
int main() {
// 读入文本
char str[1000];
fgets(str, sizeof(str), stdin);
// 统计单词频率
std::unordered_map<std::string, int> word_count;
std::stringstream ss(str);
std::string word;
while (ss >> word) {
++word_count[word];
}
// 输出结果
std::cout << "Word" << "\t" << "Frequency" << std::endl;
for (const auto& p : word_count) {
std::cout << p.first << "\t" << p.second << std::endl;
}
return 0;
}