题目描述
Trie树又称单词查找树,是一种树形结构,如下图所示。
它是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来节约存储空间,最大限度地减少无谓的字符串比较,查询效率比哈希表高。
输入的一组单词,创建Trie树。输入字符串,计算以该字符串为公共前缀的单词数。
(提示:树结点有26个指针,指向单词的下一字母结点。)
输入
测试数据有多组
每组测试数据格式为:
第一行:一行单词,单词全小写字母,且单词不会重复,单词的长度不超过10
第二行:测试公共前缀字符串数量t
后跟t行,每行一个字符串
输出
每组测试数据输出格式为:
第一行:创建的Trie树的层次遍历结果
第2~t+1行:对每行字符串,输出树中以该字符串为公共前缀的单词数。
输入样例
abcd abd bcd efg hig
3
ab
bc
abcde
输出样例
abehbcficddggd
2
1
0
解题思路
这道题本人结合字典树,深度优先搜索和广度优先搜索的知识进行解答,字典树的建立其实与二叉树的建立相似,只是左右孩子变成了26个孩子,对这棵字典树进行深度优先搜索就是每一个单词,而这道题的第一个要求其实就是进行一次广度优先搜索,然后寻找前缀其实就是对树进行深度优先搜索,搜索到这个前缀后,以前缀的最后一个字母为根节点,深度优先搜索有多少子树,也就是有多少单词以这个词组为前缀,最后实现代码如下:
#include<iostream>
#include<string>
#include<queue>
using namespace std;
int sum;
class Trie {
public:
bool flag = false;
Trie* next[26] = { nullptr };
friend void BFS();
void insert(string str) {
Trie* node = this;
for (int i = 0; i < str.length(); i++) {
char c = str[i];
if (node->next[c - 'a'] == nullptr) {
node->next[c - 'a'] = new Trie();
}
node = node->next[c - 'a'];
}
node->flag = true;
}
int searchStart(string pre) {
Trie* node = this;
sum=0;
for (int i = 0; i < pre.length(); i++) {
char c = pre[i];
if (node->next[c - 'a'] == nullptr) return 0;
node = node->next[c - 'a'];
}
DFS(node);
return sum;
}
void DFS(Trie* Node) {
Trie* tr = new Trie();
tr = Node;
int temp=0;
for (int i = 0; i < 26; i++) {
if (tr->next[i])
{
DFS(tr->next[i]);
temp = 1;
}
}
if (temp == 0) {
sum++;
return;
}
}
};
void BFS(Trie* Tree) {
queue<Trie*>q;
q.push(Tree);
while (!q.empty()) {
Trie* t = q.front();
q.pop();
for (int i = 0; i < 26; i++) {
if (t->next[i]) {
cout <<char( 'a' + i);
q.push(t->next[i]);
}
}
}
}
int main() {
string arr;
Trie* tree=new Trie();
int t;
while (1) {
cin >> arr;
if (arr[0] >= '0' && arr[0] <= '9') {
t = arr[0] - '0';
break;
}
tree->insert(arr);
}
BFS(tree);
cout << endl;
while (t--) {
string test; cin >> test;
cout << tree->searchStart(test)<<endl;
}
}
注:代码质量较低,只作解题用,没进行格式化编写