【问题标题】:Trie Tree Initialization特里树初始化
【发布时间】:2018-10-12 16:53:52
【问题描述】:

我正在使用 C++ 构建一个包含字典中的一堆单词的 trie 树。这就是我定义 TrieNode 并构建树的方式:

struct TrieNode {
    TrieNode *children[26];
    bool isWord;
    TrieNode(): isWord(false) {}  /* to be deleted */
};

void buildTree(TrieNode *root, string word) {
    TrieNode *cur = root;
    for (char c : word) {
        if (!cur->children[c-'a'])
            cur->children[c-'a'] = new TrieNode();
        cur = cur->children[c-'a'];
    }
    cur->isWord = true;
}

这在某些编译器上运行良好,但在其他编译器上会产生一些奇怪的结果。比如有一次发现isWord被初始化为152,整个程序就崩溃了。我尝试在代码中删除上面标记的行,事情又解决了。这是怎么回事?

另外,“new TrieNode()”和“new TrieNode”有什么区别?有时我发现它们也会产生不同的结果。

【问题讨论】:

  • 这是怎么回事? -- 你的程序有错误。这就是它的要点。
  • 请为您的孩子使用std::array<TrieNode*, 26>。并使用 children.at(idx) 而不是 children[idx] 访问它,因为您没有任何检查该字符串是否只有小的字母字符,您可能会访问超出范围的内存,这可能是您编写 152 的方式isWord 布尔值
  • “new TrieNode()”和“new TrieNode”有什么区别 -- 你没有在默认构造函数中初始化指向nullptr的指针数组. 那是你会注意到差异的时候。
  • TrieNode 看起来可能正在泄漏TrieNodes。没有 MCVE 很难确定。它也没有观察到Rule of Three/Five,这可能是一个非常有趣的错误源。

标签: c++ trie


【解决方案1】:

您的代码的问题在于您假设要初始化成员。不幸的是,this is not true。所以指向children 的指针不一定初始化为nullptr,这会导致您的代码取消引用无效指针,从而导致未定义的行为(UB)(例如内存损坏、崩溃等)。

简单的解决方案:

在类中为你的数组添加一个默认初始化器:

       TrieNode *children[26]{};

Demo

我的建议:

  • 使用向量而不是原生数组。它们的默认构造函数确保它们为空。
  • 阅读这篇关于initialisation的文章
  • 进行一些边界检查,因为如果您的数据中丢失了一些大写字母,您将超出范围,再次,UB。

【讨论】:

  • 非常感谢!我只是自己想通了。你是对的,因为我定义了自己的构造函数,所以我需要确保所有成员都正确初始化。另一种方法是只使用默认构造函数,它将所有 children[26] 设置为 nullptr 并将 isWord 设置为 false。
猜你喜欢
  • 2014-04-27
  • 2015-06-27
  • 1970-01-01
  • 1970-01-01
  • 2023-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多