trie(字典树)
模板题
由于找不到最直接的模板,就拿了一个最裸的题权当模板
大体思路
应用&结构:用于实现字符串快速检索的多叉树结构
总思路其他博客已经很详尽,这里不再赘述(其实懒得画图)
定义&初始化
定义trie[SIZE][30]
(假设只有小写字母),trie[i][j]
表示当前在i结点,编号为j的子结点所处的位置,(我们称字符'a'的编号为0,'b'为1,以此类推),即trie是一个用于模拟指针的数组,定义一个特殊的空结点(一般为0),所有的指针均指向空
定义end[SIZE]
,end[i]
表示下标为i的结点是否为某个字符串的终点
插入
void insert(char *s , int siz) {
static int top = 1;//trie的第一维最大下标,类似于链式前向星
int p = 1;
for(int i = 1 ; i <= siz ; i++) {
int c = s[i] - 'a';
if(trie[p][c] == 0)//如果指向空,则新建结点
trie[p][c] = ++top;
p = trie[p][c];
}
vis[p] = false;
end[p] = true;
}
查找(以模板为例)
int search(char *s , int siz) {
int p = 1;
for(int i = 1 ; i <= siz ; i++) {
p = trie[p][s[i] - 'a'];
if(p == 0) return 0;//当前字符串在trie树中不存在
}
if(end[p] == false) return 0;//WRONG
if(vis[p] == true) return 2;//REPEAT
vis[p] = true;//标记当前字符串已经访问过
return 1;//OK
}
模板题完整代码
#include <iostream>
#include <cstdio>
#define nn 500010
using namespace std;
int sread(char *s) {
int siz = 1;
do
s[siz] = getchar();
while(s[siz] < 'a' || s[siz] > 'z');
while(s[siz] >= 'a' && s[siz] <= 'z')
s[++siz] = getchar();
--siz;
return siz;
}
bool vis[nn] , end[nn];
int trie[nn][30];
void insert(char *s , int siz) {
static int top = 1;
int p = 1;
for(int i = 1 ; i <= siz ; i++) {
int c = s[i] - 'a';
if(trie[p][c] == 0)
trie[p][c] = ++top;
p = trie[p][c];
}
vis[p] = false;
end[p] = true;
}
int search(char *s , int siz) {
int p = 1;
for(int i = 1 ; i <= siz ; i++) {
p = trie[p][s[i] - 'a'];
if(p == 0) return 0;
}
if(end[p] == false) return 0;//WRONG
if(vis[p] == true) return 2;//REPEAT
vis[p] = true;
return 1;//OK
}
int n , m;
char s[nn];
int main() {
cin >> n;
for(int i = 1 ; i <= n ; i++) {
int siz = sread(s);
insert(s , siz);
}
cin >> m;
for(int i = 1 ; i <= m ; i++) {
int siz = sread(s);
int res = search(s , siz);
if(res == 0)
puts("WRONG");
else if(res == 1)
puts("OK");
else
puts("REPEAT");
}
return 0;
}