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;
}
posted @ 2020-11-19 12:04  追梦人1024  阅读(160)  评论(0编辑  收藏  举报