【问题标题】:Printing a trie lexicographically in c在 c 中按字典顺序打印 trie
【发布时间】:2015-10-10 21:24:06
【问题描述】:

所以我正在尝试将单词存储在字典文件中。我已经实现了插入操作;现在我正在尝试按字典顺序打印。我快得到它了,但我有一个小问题,我不知道如何解决。我还试图记住我的程序的速度,这就是为什么我选择了数组或链表的 trie。 这是单个节点的样子:

struct node {
  int end;
  int occurrences;
  int superwords;
  struct node* child[26];
};

"end" 表示一个单词的完成(例如,单词 book 中字母 'k' 处的 end == 1;这可以防止在检查单词是否已实际插入树中时产生混淆)。

方法如下:

void preorder(struct node *follow, char hold[200], int s){
  int i = 0;
  if(follow == NULL){
    return;
  }

  for(i = 0; i < 26; i++){
    if(follow->child[i] == NULL){
      continue;
    }
    else{
      printf("%c",'a'+i);
      hold[s] = 'a'+i;
      s++;
      if(follow->child[i]->end == 1){
        printf("\n");
        hold[s] = '\0';
        printf("%s", hold);
      }
      preorder(follow->child[i], hold, s);
    }
  }
  return;
}

我插入的词是:boo、book、booking、john、tex、text。它们应该按该顺序打印并分开行。我的输出如下:

boo
book
booking
bookingjohn
bjohntex
bjtext
bjtext

我知道这可能与我的“保持”数组有关,该数组存储单词的前缀,因此它们不会丢失。我需要在某处将索引设置回零以指示前缀及其所有相关单词(嘘,书,预订是一个很好的例子)的完成,但没有成功。任何帮助将不胜感激,我很乐意进一步澄清我的思考过程。

【问题讨论】:

  • 您对静态变量的概念有多熟悉?因为这个函数是递归的,所以最好使用一个或两个静态变量来跟踪函数调用之间应该记住的信息。
  • 不是很熟悉。我是 c 的新手。请详细说明。
  • 我认为与其使用s++,不如将​​s+1 传递给对preorder 的递归调用。这通常是您处理下降的方式,同时允许您在返回时进行备份。在打印之前,您还必须在 s+1 处为空终止。
  • @Sara 静态变量在函数调用之间保留其值。下次调用该函数时,该变量将保留上次为它分配值时的值。
  • @JoelTrauger 谢谢,我会记住的。

标签: c sorting trie lexicographic preorder


【解决方案1】:

你很亲密。

有两个问题,都在贯穿 trie 分支的 for 循环中:

else{
  printf("%c",'a'+i);
  hold[s] = 'a'+i;
  s++;

第一个问题是您(几乎)将所有内容打印两次。在上面的 sn-p 中,您在跟踪树时打印前缀。然后,当您到达单词的末尾时,您会打印整个单词:

  if(follow->child[i]->end == 1){
    printf("\n");
    hold[s] = '\0';
    printf("%s", hold);
  }

所以根本不需要打印前缀,重复打印很混乱。

其次,s 参数表示树中的深度,即当前前缀的长度。所以在探索一个 trie 节点的过程中它应该是恒定的。但是每次你找到一个新分支时,你都会增加它(s++ 在上面的第一个 sn-p 中)。而不是这样做,您需要递归调用以使用 s + 1 作为其参数,以便使用正确的前缀长度调用它。

您还可以稍微简化控制结构。

这是一个例子:

void preorder(struct node *follow, char hold[200], int s){
  int i = 0;
  if(follow == NULL){
    return;
  }
  /* Print the word at the beginning instead of the end */
  if (follow->end) {
    hold[s] = 0;
    printf("%s\n", hold);
  }

  for(i = 0; i < 26; i++){
    /* preorder returns immediately if its argument is NULL, so
     * there's no need to check twice. Perhaps even better would be
     * to do the check here, and not do it at the beginning.
     */
    hold[s] = 'a'+i;
    preorder(follow->child[i], hold, s + 1);
  }
}

【讨论】:

  • 我想出了几乎完全相同的解决方案。我有hold[s] = 0,而不是s+1。你确定索引吗?
  • @DanielStevens:不,你是对的。在调用树中将其上移一级意味着它应该是s。谢谢。
  • 非常感谢。我觉得我的代码太复杂了,一天的工作让我对简化视而不见。你的解释很有道理。
猜你喜欢
  • 2013-07-24
  • 2016-05-17
  • 1970-01-01
  • 1970-01-01
  • 2021-06-24
  • 1970-01-01
  • 2019-06-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多