题目描述
Trie树又称单词查找树,是一种树形结构,如下图所示。
它是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。
它的优点是:利用字符串的公共前缀来节约存储空间,最大限度地减少无谓的字符串比较,查询效率比哈希表高。
输入的一组单词,创建Trie树。输入字符串,计算以该字符串为公共前缀的单词数。
(提示:树结点有26个指针,指向单词的下一字母结点。)
输入
测试数据有多组
每组测试数据格式为:
第一行:一行单词,单词全小写字母,且单词不会重复,单词的长度不超过10
第二行:测试公共前缀字符串数量t
后跟t行,每行一个字符串
输出
每组测试数据输出格式为:
第一行:创建的Trie树的层次遍历结果
第2~t+1行:对每行字符串,输出树中以该字符串为公共前缀的单词数。
输入输出样例
输入样例1 <-复制
abcd abd bcd efg hig
3
ab
bc
abcde
输出样例1
abehbcficddggd
2
1
0
解题思路
这道题说简单点就是建了一个目录树,按照输入输出样例画个图就很容易明白了。
在这个树中,你可以找到输入的所有样例,即abcd abd bcd efg hig。
层次遍历就是一层一层的往下遍历,abeh-bcfi-cddgg-d,即输出样例的abehbcficddggd。
首先就是建立目录树,然后bfs搜索输出层次遍历结果。
最后dfs查找前缀出现次数,就是以某个节点为根节点,搜索有多少个叶子结点。
例如dfs查找前缀ab出现次数,相当于以第一分支的b为根节点,寻找叶子结点,即abcd的d、abd的d,叶子结点有两个,故出现次数为2。
理清了思路,实现就很简单了。
AC代码
#include<iostream>
#include<string>
#include<queue>
using namespace std;
// 定义前缀树的节点结构
struct node
{
char fu; // 当前节点的字符
int shu = 0; // 当前节点字符的出现次数
node* next[26] = { NULL }; // 指向下一个节点的指针数组,包含 26 个小写字母
};
node* root; // 根节点指针
// 创建前缀树
void create(string str)
{
int len = size(str);
int i, k;
node* p = root;
for (i = 0; i < len; i++)
{
k = str[i] - 'a'; // 计算当前字符对应的索引
if (p->next[k] == NULL)
{
node* s = new node;
s->fu = str[i];
p->next[k] = s;
}
p->next[k]->shu++;
p = p->next[k];
}
}
// 广度优先搜索遍历前缀树
void bfs(node* root)
{
node* p = root;
queue<node*>q;
int i;
for (i = 0; i < 26; i++)
{
if (p->next[i] != NULL)
q.push(p->next[i]);
}
while (!q.empty())
{
p = q.front();
q.pop();
cout << p->fu; // 输出当前节点的字符
for (i = 0; i < 26; i++)
{
if (p->next[i] != NULL)
q.push(p->next[i]);
}
}
cout << endl;
}
// 深度优先搜索遍历前缀树
void dfs(string str)
{
int len = size(str);
int i, k;
node* p = root;
for (i = 0; i < len; i++)
{
k = str[i] - 'a'; // 计算当前字符对应的索引
p = p->next[k];
if (p == NULL)
{
cout << "0" << endl; // 如果遍历到空节点,说明前缀不存在,输出 0
return;
}
if (i == len - 1)
{
cout << p->shu << endl; // 输出当前节点的出现次数
return;
}
}
}
int main()
{
string str;
root = new node;
int t;
while (1)
{
cin >> str;
if (str[0] >= '0' && str[0] <= '9')
{
t = str[0] - '0';
break;
}
create(str); // 构建前缀树
}
bfs(root); // 广度优先搜索输出层次遍历结果
while (t--)
{
cin >> str;
dfs(str); // 深度优先搜索,输出前缀的出现次数
}
return 0;
}
(by 归忆)