trie搜索中存在逻辑缺陷

Logic flaw in trie search

本文关键字:缺陷 存在 搜索 trie      更新时间:2023-10-16

我目前正在进行一个trie实现练习,遇到了一个心理障碍。

问题出在我的搜索功能上。我正试图让我的trie树能够在将字符串加载到程序内存后,从提供的前缀中检索字符串列表。

我也知道我可能在使用队列/不应该在C++等中使用C函数。。可以说,这只是一个"草稿"。

这就是我目前所拥有的:

bool SearchForStrings(vector<string> &output, string data)
{
Node *iter = GetLastNode("an");
Node *hold = iter;
stack<char> str;

while (hold->visited == false)
{
int index = GetNextChild(iter);
if (index > -1)
{
str.push(char('a' + index));
//current.push(iter);
iter = iter->next[index];
}
//We've hit a leaf so we want to unwind the stack and print the string
else if (index < 0 && IsLeaf(iter))
{
iter->visited = true;
string temp("");
stringstream ss;
while (str.size() > 0)
{
temp += str.top();
str.pop();
}
int i = 0;
for (std::string::reverse_iterator it = temp.rbegin(); it != temp.rend(); it++)
ss << *it;
//Store the string we have
output.push_back(data + ss.str());
//Move our iterator back to the root node
iter = hold;
}
//We know this isnt a leaf so we dont want to print out the stack
else
{
iter->visited = true;
iter = hold;
}

}
return (output.size() > 0);
}
int GetNextChild(Node *s)
{
for (int i = 0; i < 26; i++)
{
if (s->next[i] != nullptr && s->next[i]->visited == false)
return i;
}
return -1;
}
bool IsLeaf(Node *s)
{
for (int i = 0; i < 26; i++)
{
if (s->next[i] != nullptr)
return false;
}
return true;
}
struct Node{
int value;
Node *next[26];
bool visited;
};

代码太长,或者我会把它全部发布,GetLastNode()会在传入数据的末尾检索节点,所以如果前缀是"su",字符串是"substring",则节点将指向"u",用作人工根节点

(可能完全错误…只是在这里键入,没有测试)类似于:

首先,我们需要一种方法来指示节点代表一个条目。

所以让我们有:

struct Node{
int value;
Node *next[26];
bool entry;
};

我已经删除了你的访问标志,因为我没有使用它。

您应该修改插入/更新/删除功能以支持此标志。如果该标志为true,则表示该节点上有一个实际条目。

现在我们可以修改

bool isLeaf(Node *s) {
return s->entry;
}

这意味着当有入口时,我们会考虑一片叶子。。。也许现在名称是错误的,因为可能有子级(带有"any"answers"anywhere"的"y"节点是叶子,但它有子级)

现在搜索:

首先是一个可以调用的公共函数。

bool searchForStrings(std::vector<string> &output, const std::string &key) {
// start the recursion
// theTrieRoot is the root node for the whole structure
return searchForString(theTrieRoot,output,key);
}

然后是将用于递归的内部函数。

bool searchForStrings(Node *node, std::vector<string> &output, const std::string &key) {
if(isLeaf(node->next[i])) {
// leaf node - add an empty string.
output.push_back(std::string());
} 
if(key.empty()) {
// Key is empty, collect all child nodes.
for (int i = 0; i < 26; i++)
{
if (node->next[i] != nullptr) {
std::vector<std::string> partial;
searchForStrings(node->next[i],partial,key);
// so we got a list of the childs,
// add the key of this node to them.                
for(auto s:partial) {
output.push_back(std::string('a'+i)+s)
}
}
} // end for
} // end if key.empty
else {
// key is not empty, try to get the node for the
// first character of the key.
int c=key[0]-'a';
if((c<0 || (c>26)) {
// first character was not a letter.
return false;
}
if(node->next[c]==nullptr) {
// no match (no node where we expect it)
return false;
}
// recurse into the node matching the key
std::vector<std::string> partial;
searchForStrings(node->next[c],partial,key.substr(1));
// add the key of this node to the result
for(auto s:partial) {            
output.push_back(std::string(key[0])+s)
}            
}
// provide a meaningful return value
if(output.empty()) {
return false;
} else {
return true;
}
}

而"一个"搜索的执行是。

  • 调用searchForStrings(root,[],"an")
    • 根不是叶,键不是空的。匹配由"a"键控的下一个节点
    • 调用searchForStrings(节点(a),[],"n")
      • 节点(a)不是叶,键不是空的。匹配由"n"键控的下一个节点
      • 调用searchForStrings(node(n),[],")
        • 节点(n)不是叶,键为空。需要在所有非null子级上递归:
        • 调用searchForStrings(节点,[],")
          • 节点不是叶,键是空的,需要在所有非空的子级上递归:
          • 。。。最终我们将到达Node(r),它是一个叶节点,因此它将返回一个["],返回时它将被添加["r"]->["er"]->"wer"]->["swer"]
        • 调用searchForStings(node(y),[],")
          • node(y)为leaf(在输出中添加"),key为空
          • 递归,我们将得到["时间"]
          • 我们将返回[","time"]
        • 此时,我们将添加"y"以获得["y","ytime"]
      • 在这里,我们将添加"n"以获得["nswer"、"ny"、"nytime"]
    • 添加"a"以获得["answerswer"、"any"、"anytime"]
  • 我们完了