【定义】
Trie树,即字典树,又称单词查找树或键树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:最大限度地减少无谓的字符串比较,查询效率比哈希表高。
【目的】
Trie的核心思想是空间换时间。利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。
【基本性质】
- 根节点不包含字符,除根节点外每一个节点都只包含一个字符。
- 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。
- 每个节点的所有子节点包含的字符都不相同。
【构建】
这图里的单词有,b bcd abc abd abcd efg hij
【模板代码理解】
#include<cstdio>
#include<cstdlib>
#include<iostream>
using namespace std;
#define maxn 26
struct tire
{
bool end; //判断是否为一个单词的结尾
struct tire *nex[maxn]; //分支
};
void insert(tire *root, const char *s) //将单词s插入字典树root中
{
if (root == NULL || *s == '\0') //当树root为空或者单词为空 直接返回
return;
tire *p = root; //让指针p等于树的头结点root,这是为了保护root
while (*s != '\0') //从单词第一个字母开始插入,直到整个单词完全被插入。
{
if (p->nex[*s - 'a'] == NULL) //如果下一个结点不存在,则证明之前无这个单词前缀存在过
{
tire *temp = (tire *)malloc(sizeof(tire)); //创建一个分支temp,比如a
for (int i = 0; i<maxn; i++)
temp->nex[i] = NULL; //让这个分支的分支都为NULL,代表a后面暂时无其他分支
temp->end = false; //这个字母并不是单词结尾,所以标记为false
p->nex[*s - 'a'] = temp; //让创建好的这个分支赋值给树p.
p = p->nex[*s - 'a']; //让此时的树节点指向已经创建好的分支,进行后面的继续添加分支。
}
else
p = p->nex[*s - 'a']; //已经有这个分支存在,那么让p直接指向这个树节点
s++; //指针增加,开始进行后面单词的添加。
}
p->end = true; //此时p结点为这个单词的最后一个单词,标记单词这里是一个单词的结尾。
}
int search(tire *root, const char *s) //查找此单词是否存在
{
tire *p = root;
while (p != NULL && *s != '\0')
{
p = p->nex[*s - 'a']; //让p指向下一个结点,一直遍历下去。
s++;
}
return (p != NULL && p->end == true); //当满足条件则返回1,不满足返回0
}
void del(tire *root) //释放整个字典树占的堆区空间
{
for (int i = 0; i<maxn; i++)
{
if (root->nex[i] != NULL)
{
del(root->nex[i]);
}
}
free(root);
}
int main()
{
int n, m;//n为tire输入的单词数,m为要查找的单词数
char s[100];
tire *root = (tire *)malloc(sizeof(tire));
for (int i = 0; i<maxn; i++)
root->nex[i] = NULL;
root->end = false;
scanf("%d", &n);
getchar();
for (int i = 0; i<n; i++)
{
scanf("%s", s);
insert(root, s);
}
while (scanf("%d", &m) != EOF)
{
for (int i = 0; i<m; i++)
{
scanf("%s", s);
/*int flag = search(root, s); //验证查找的时候返回的是什么
printf("flag=%d\n", flag);*/
if (search(root, s) == 1)
printf("yes\n");
else
printf("no\n");
}
printf("\n");
}
del(root);
return 0;
}