如何在C中填充trie?

时间:2014-11-01 23:20:19

标签: c struct trie

我正在尝试编写一个程序,它接受单词并创建一个trie,trie的每个节点都是一个包含一个单一字符的结构。

我有一个将char *解析为单词的函数(假设char *只包含小写字母)。当每个单词取自char *时,它将传递给函数addWordOccurrence(const char* word, const int wordLength, struct tNode root)addWordOccurrence()应该检查单词的第一个字母是否在root.branches[i]中,因为我在循环中递增,检查root.branches的每个可能索引(对于所有的{0}都是0-25小写字母的字母)。如果第一个字母不在root.branches中,则会创建包含新字母的新结构tNode。然后继续到单词的第二个字母,将它与新制作的结构tNode的分支进行比较,依此类推......

我们尝试过的第一个词是“医生”,我的特里取第一个字母'd'并将其添加到root.branches[0]然后取'o'并将其添加到root.branches[0].branches[0],哪个是对的。但随后它将医生中的'd'添加到其分支的下一个17个索引(所以root.branches[0].branches[1] through [18]),这不应该是这种情况。请帮忙!

struct tNode{
  char c;
  int occurrences;
  struct tNode *branches;
};

int addWordOccurrence(const char* word, const int wordLength, struct tNode root){
//declare fields
int counter, i,k,firstNull;
counter = 0;
while(1){
  if(counter >= wordLength){
    break;
  }
  //traverse through the word letter by letter
  for(i=0; i<wordLength; i++){
    //compare each letter to the branches of root until the letter is found or first null space
    for(k=0; k<26; k++){
    //if the letter is a branch already set root to the struct of that letter in branches
       if(root.branches[k].c == word[i]){
          root = root.branches[k];
          break;
       }
    }
    //the current letter of the word is not in branches
    //go through branches to find position to add the new tNode
    for(firstNull=0; firstNull<26; firstNull++){
       //set firstNull equal to the index of the first null value in branches
       if(root.branches[firstNull].c  <  'a' || root.branches[firstNull].c > 'z' ){
          break;
       }
    }
    //add a new node to branches
    root.branches[firstNull].c = word[i];
    root.branches[firstNull].occurrences = 0;
    root.branches[firstNull].branches = malloc(sizeof(struct tNode) * 26);
    if(counter != wordLength){
       root = root.branches[firstNull];
    }
    counter++;
    if(counter == wordLength-2){
       root.occurrences++;
    }
 }
}
 return 0;
}

1 个答案:

答案 0 :(得分:0)

您的实施存在许多问题:

  1. 这是一个奇怪的设计,具有随机排列的字母表。必须在每个级别上对你想要的字母进行线性搜索,这首先打破了做一个特里的目的。
  2. 执行root = root.branches[k];时,您正在创建变量的副本。现在,由于通过指针访问事物,在这种情况下它可能适合你,但它实际上只是在寻找麻烦。
  3. 当您在循环中分配节点时,您不会初始化它,这意味着它充满了垃圾/未知数据并导致问题。
  4. 您的实施不必要地复杂,就像您的外部while (1)循环一样。
  5. 对于一个非常简单的特里,我会做类似的事情:

    struct tNode {
      bool isWord;
      struct tNode *branches[26];
    };
    
    void addWordOccurrence (const char* word, const int wordLength, struct tNode* pRoot) {
       int i;
       int nodeIndex;
       tNode* pCurrentNode = pRoot;
    
       for (i = 0; i < wordLength; ++i)
       {
           nodeIndex = tolower(word[i]) - 'a'; 
    
           if (nodeIndex >= 0 && nodeIndex <= 25)
           {
                if (pCurrentNode->branches[nodeIndex] == NULL)
                {
                    pCurrentNode->branches[nodeIndex] = calloc(1, sizeof(tNode));
                }
    
                pCurrentNode = pCurrentNode->branches[nodeIndex];
           }
       }
    
       pCurrentNode->isWord = true;
    }
    

    您可以使用struct tNode *branches;但它实际上只是添加了您不需要的另一个分配步骤。您使用字符的ASCII值将branches[0]分配给'a',将branches[25]分配给'z'......不需要搜索真正会破坏特里表现的“免费”点。最后,你需要一个像isWord这样的终结符,以便知道“医生”是一个单词而“docto”不是。