【问题标题】:How to make trie store reincidence of a word in C如何在C中使trie存储一个单词的reincidence
【发布时间】:2017-06-20 04:29:04
【问题描述】:

我的 trie 的当前节点存储一个字符和一个位置(这是当前正在读取的单词在文本中结束的位置)。

如果我在位置 100 读到一个单词“foo”,在位置 200 读到另一个单词“foo”,我的节点如何存储这 2 次出现?有没有一种快速的方法(使用数组或更快的实现方式)或者我需要实现链表?

【问题讨论】:

  • 当元素个数未知且没有预先使用无用区域时,当使用数组时,随着元素个数的增加,扩展数组的过程变得不利。如果在这种情况下不需要随机访问,则链表是有利的。在处理少量数据时,两者都没有太大区别。(数组可能有优势,但实际时间无关紧要)
  • 两者差别不大 --> 差别不大。
  • 在维基百科上有一个很好的Trie - Implementation strategies介绍。

标签: c string-matching trie


【解决方案1】:

所以,你的 trie 节点看起来像

struct trie_node {
    struct trie_node *next;
    strict trie_node *child;
    wchar_t           character;
    off_t             position;
};

当然,如果数据始终在内存中,您可以使用size_t position;

如果我们假设许多前缀没有映射到特定位置(因为它们不是完整的单词),那么为位置使用单独的数组可能会很有用,即。

struct positions {
    size_t            count_max;
    size_t            count;
    off_t             position[];
};

struct trie_node {
    struct trie_node *next;
    struct trie_node *child;
    wchar_t           character;
    struct positions *position;
};

不对应完整单词的字符节点可以有一个 NULL position 成员。 count_max 对应于分配的位置数,count 对应于当前位置数。必要时可以重新分配数组并调整其大小。这种数组大小调整在实际应用中很常见; (重新分配的)开销被认为是完全可以接受的,尤其是与替代方案相比。


另一个有趣的选择是使用线性数组来按出现的顺序表示文本中的单词,trie 节点中的position 成员指定数组中第一次出现的索引。每个数组条目将包含下一次出现的索引,以及可选的返回 trie 节点的链接:

#include <stdlib.h>
#include <limits.h>

struct trie_node {
    struct trie_node  *next;
    struct trie_node  *child;
    wchar_t            character;
    size_t             index;     /* NO_INDEX if no occurrences */
    size_t             occurs;    /* Num of occurrences, optional */
    wchar_t            word[];    /* Optional, entire word */
};

/* When 'index' refers to 'none', use: */
#define  NO_INDEX  SIZE_MAX

struct occurrence {
    off_t              offset;
    size_t             next;
    struct trie_node  *node;    /* Optional */
};

一个容器结构会有数组,而 trie 会挂掉它:

struct text {
    size_t             count_max;
    size_t             count;
    struct occurrence *occurrences;
    struct trie_node  *trie;
};

然后,您的函数将采用指向 struct text 的指针。

struct text 中的occurrences 数组可以根据需要动态重新分配。 (这也是为什么 trie 节点中的first 成员是数组的索引,而不是指针:如果它是指针,我们可能必须遍历整个 trie 才能更新所有节点的指针,在重新分配数组时,否则。)

请注意,因为我们使用size_t 作为数组的索引,NO_INDEX 是可能的最大值,而size_t 是无符号整数类型,检查if (i &lt; count) 来验证索引就足够了i 有效。

对应一个完整单词的每个 trie 节点都有index != NO_INDEX,C99 灵活数组成员word 初始化为完整单词(包括结尾的L'\0')。 occurs 成员将拥有该词的出现次数,如果它有用。 (没有需要,除了我们人类可能对每个单词的出现次数感兴趣。)

此方案允许直接访问文本中的单词序列。

如果出现在数组中的偏移量增加,则可以使用二进制搜索来查找特定偏移量之间的单词。因为每次出现都有一个指向 trie 节点的反向链接,该节点包含 word 成员中的完整单词,所以很容易打印出文件中出现的任何单词,而无需扫描整个 trie。

我写了这个答案,因为我想展示如何以这种方式组合两个非常不同的数据结构,可以开辟访问数据的非常有效的方法。我不能说它是否有用,因为有用性取决于正在解决的问题。

【讨论】:

    猜你喜欢
    • 2011-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-18
    • 1970-01-01
    • 1970-01-01
    • 2013-04-07
    • 2021-11-24
    相关资源
    最近更新 更多