用和kmp相似的思路,将trie树变为trie图。以用于在长篇文章中查找是否存在字典中的单词。
在此强调本文中的‘根’和一般的树中的‘根’不一样!
1.建立trie树
①建立一个结点结构体和初始化函数
typedef struct node{
bool isEnd;//结点是否为单词的结尾
struct node* trie;//结点的根(这里的根和一般的树的根不一样,但是怎么解释呢。不知道啊。)
struct node* next[26];
}TrieNode;
void initNode(TrieNode *p)
{
p->isEnd = 0;
for(int i=0;i<26;i++)
p->next[i]=NULL;
}
②建立一个head结点并初始化。
③建立一个headTrie结点作为head的根,并将其所有的next指向head。
④对于输入单词的处理:
输入一个字符串并扫描,只要还没结束:
并判断是否存在对应字符的子结点。
若存在,转到子结点;否者建一个子结点并转到该结点。
当单词扫描结束时,将最后一个结点的isEnd属性标为true。
void makeTrie(char *w)
{
int i=0;
TrieNode* p=&head;
while(w[i])
{
if(p->next[w[i]-97])
{
p=p->next[w[i]-97];
}
else
{
TrieNode *q=(TrieNode *)malloc(sizeof(TrieNode));
initNode(q);
p->next[w[i]-97]=q;
p=q;
}
i++;
}
p->isEnd=1;
}
用广度遍历。将&head加入遍历队列,并将head.trie赋值为&headTrie作为head的根。
只要遍历队列里还有元素,则做一下操作:
①先取出元素。
②判断是否存在对应字符的子结点。
若有,则将其子结点加入遍历队列,并将其子结点的根结点设为其根结点的对应字符的子结点。。。。。文字好绕,上代码p->next[i]->trie=p->trie->next[i];
若无,则将其对应的子结点设为其根结点的对应字符的子结点。p->next[i]=p->trie->next[i];
这里就是用的kmp的思想。
void makeTrieMap()
{
int front=0,rear=0;
queue[rear++]=&head;
head.trie=&headTrie;
while(front<rear)
{
TrieNode* p=queue[front++];
for(int i=0;i<26;i++)
{
if(p->next[i]!=NULL)
{
queue[rear++]=p->next[i];
p->next[i]->trie=p->trie->next[i];
}
else
{
p->next[i]=p->trie->next[i];
}
}
}
}
3.使用trie图
扫描文章。
从head开始对比,一直照着next来跳转。直达有一个结点的isEnd为true。说明找到字典中的某个单词了。返回true;
否则直到扫描结束都没找到单词,返回false。
bool find(char *s)
{
int i=0;
TrieNode* p=&head;
while(s[i])
{
p=p->next[s[i]-97];
if(p->isEnd) return true;
i++;
}
return false;
}
题目全代码:
#include<cstdio>
#include<cstdlib>
using namespace std;
typedef struct node{
bool isEnd;
struct node* trie;
struct node* next[26];
}TrieNode;
TrieNode head;
TrieNode headTrie;
TrieNode* queue[1000000+1];
void initNode(TrieNode *p)
{
p->isEnd = 0;
for(int i=0;i<26;i++)
p->next[i]=NULL;
}
void makeTrie(char *w)
{
int i=0;
TrieNode* p=&head;
while(w[i])
{
if(p->next[w[i]-97])
{
p=p->next[w[i]-97];
}
else
{
TrieNode *q=(TrieNode *)malloc(sizeof(TrieNode));
initNode(q);
p->next[w[i]-97]=q;
p=q;
}
i++;
}
p->isEnd=1;
}
void makeTrieMap()
{
int front=0,rear=0;
queue[rear++]=&head;
head.trie=&headTrie;
while(front<rear)
{
TrieNode* p=queue[front++];
for(int i=0;i<26;i++)
{
if(p->next[i]!=NULL)
{
queue[rear++]=p->next[i];
p->next[i]->trie=p->trie->next[i];
}
else
{
p->next[i]=p->trie->next[i];
}
}
}
}
bool find(char *s)
{
int i=0;
TrieNode* p=&head;
while(s[i])
{
p=p->next[s[i]-97];
if(p->isEnd) return true;
i++;
}
return false;
}
int main()
{
int N;
char word[1000000+1];
char str[1000000+1];
initNode(&head);
for(int i=0;i<26;i++)
headTrie.next[i]=&head;
scanf("%d",&N);
while(N--)
{
scanf("%s",word);
makeTrie(word);
}
makeTrieMap();
scanf("%s",str);
if(find(str)) printf("YES");
else printf("NO");
return 0;
}