Trie字典树递归遍历中如何存储所有单词到数组且不被覆盖?
问题根因
你每次调用strcpy(storeList, words)都是从storeList数组的首地址写入新单词,后写入的内容必然会覆盖之前已存储的内容。
修改方案
新增一个偏移量参数记录storeList当前可写入的起始位置即可:
- 给
printALLWords函数新增引用传递的偏移量参数,递归过程中修改的偏移量可以全局生效 - 每次写入单词时从偏移位置开始写入,写入完成后更新偏移量,跳过当前单词的长度和结尾的
\0占位
修改后的完整代码
#include <iostream> #include <cstring> class TrieNode{ public: TrieNode* children[26]; bool isEndOfWord; char letter; TrieNode(){ for(int i = 0; i < 26; i++){ this->children[i] = NULL; } this->isEndOfWord = false; } void insert(TrieNode* root, std::string word){ for(int i = 0; i < word.size(); i++){ int index = word[i] - 'a'; if(root->children[index] == NULL){ root->children[index] = new TrieNode(); root->letter = word[i]; } root = root->children[index]; } root->isEndOfWord = true; } // 新增引用传递的offset参数 void printALLWords(TrieNode* root, char words[], char storeList[], int level, int& offset){ if(root->isEndOfWord){ words[level] = '\0'; // 从偏移位置开始写入当前单词 strcpy(storeList + offset, words); // 偏移量更新:跳过当前单词长度 + 结尾的\0 offset += strlen(words) + 1; // 不要return,防止漏掉当前节点是中间节点同时也是单词结尾的情况(比如同时存car和card) } for(int i = 0; i < 26; i++){ if(root->children[i] != NULL){ char letter = 'a' + i; words[level] = letter; printALLWords(root->children[i], words, storeList, level + 1, offset); } } } }; int main(){ TrieNode* root = new TrieNode(); root->insert(root, "car"); root->insert(root, "cat"); char words[20]; char storeList[40]; int level = 0; int offset = 0; // 初始化偏移量为0 root->printALLWords(root, words, storeList, level, offset); // 遍历输出所有单词 int pos = 0; while(pos < offset) { std::cout << &storeList[pos] << std::endl; pos += strlen(&storeList[pos]) + 1; } return 0; }
补充说明
原来的递归终止分支里的return建议注释掉,避免出现当前节点既是某个单词结尾,同时还有子节点的场景下,无法继续遍历子节点的问题(比如你同时插入了car和card,如果保留return就会漏掉card)。
内容的提问来源于stack exchange,提问作者Gero M
相关产品推荐
相关产品推荐

