我目前正在哈佛做 CS50,目标是以最快的方式将字典加载到任何数据结构中。对于这个问题集,我使用的是 Trie。
我的代码背后的逻辑如下:
- 一次读一个字符。
- 如果字符已经存在,则检查 trie 的子节点,如果它等于 NULL,我们为其分配一些空间。
- 光标设置为我们刚刚分配空间的子节点。
- 如果我们到达一个单词的结尾(“\n”),我们将布尔值设置为 true 并将光标完全重置为其初始值(我们之前存储在光标->根中)。
我尝试了几种实现,其中一些有一些我不满意的逻辑错误,当我有一本大字典时,有些给我带来了分段错误。
下面是我最新实现的代码,基本上发生的情况是,将第一个单词加载到 trie 结构中是可以的,但在第二个时它失败了。然后问题在于我将新节点值设置为子节点(我们为其分配了一些空闲空间)。这背后的逻辑显然是连接树并移动到下一个节点。这是我认为错误的代码:
curser = curser->children[tolower(ch) - 'a'];
但问题是,它在我的其他一些实现中有效,只是在这个实现中它突然停止工作,并在第一个单词后给我一个分段错误。正如我所说,我是编码的初学者,所以请赐教并批评我的实现!谢谢一堆。
#include <stdbool.h>
#include <stdio.h>
#include "dictionary.h"
#include <ctype.h>
#include <stdlib.h>
typedef struct node
{
bool end;
struct node* children[27];
struct node* root;
struct node* next;
} node;
//global variable used to check the number of words in the trie
int totalwords = 0;
//root node
node* curser;
int ch;
int main(void)
{
FILE* dict = fopen("text.txt", "r");
if (dict == NULL)
{
printf("Could not open dictionary\n");
return 1;
}
curser = (struct node*) malloc(sizeof(node));
curser->root = curser;
for (ch = fgetc(dict); ch != EOF; ch = fgetc(dict))
{
if (ch == '\0')
{
curser->end = true;
curser = curser->root;
totalwords++;
printf("%i\n", totalwords);
}
else
{
if (isalpha(ch))
{
if (curser->children[tolower(ch) - 'a'] == NULL)
{
curser->children[tolower(ch) - 'a'] = (struct node*)malloc(sizeof(node));
}
curser = curser->children[tolower(ch) - 'a'];
}
else if (ch == '\'')
{
if (curser->children[26] == NULL)
{
curser->children[26] = (struct node*)malloc(sizeof(node));
}
curser = curser->children[26];
}
}
}
fclose(dict);
return false;
}
编辑:
我的另一个问题是为什么我在当前代码中无法检测到 Null Terminator \0 但它可以检测到新行 \n?我需要能够检测空终止符才能获得正确数量的单词。关于什么是错的任何建议?