找出文本中存在的坏单词-后缀trie

假设给定一个关键词rob,如果某一个单词中包含此字符串,那么就断定此字符串为bad word。如problem就包含rob,那么它就是bad word。其实这种叙述是:“判断一个字符串是否是另一个字符串的子串”的另外一种描述。熟悉字符串匹配的人都知道,这个问题可以用KMP算法很快就能够解决。但是就像我们不嫌弃自己的钱多的一样,方法多了,路子就多了。所以决定应用后缀trie来解决这个问题。后缀trie是trie树的一种变种形式。给定字符串S=s1s2s3s4....sn,把si...sn称作S的一个后缀,其中 1<=i<=n,按照次序,我们把S的每一个后缀都插入到一个trie树中,最终形成的树,就叫S的后缀trie树。对于单词problem的后缀依次为:

problem, roblem, oblem, blem, lem, em , m.给出这个单词的后缀trie:

找出文本中存在的坏单词-后缀trie_第1张图片

建立好了后缀trie便可以清楚的看到,在树中寻找rob是相当容易的事情,只需要3次比对,也就是length of “rob”的长度。可以说是如果trie建立好以后,寻找什么都是很快的。但是在建立后缀trie的时候却要耗费很大的空间和很长的时间,这就是为什么后缀trie没有被人们所亲睐的原因。仔细看图,体会一下它的奇妙之处吧,它涵盖了problem中以任何字母开头,在一定长度内的任何子串。下面给出代码,它的时间和空间复杂度都在O(n^2).

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define CHILD_NUM 26
typedef struct trie_node{
	char key;
	struct trie_node *child[CHILD_NUM];
}TrieNode, *TrieTree;

TrieNode *create_node(char key) {
	TrieNode *temp = (TrieNode*)malloc(sizeof(TrieNode));
	temp->key = key;
	for(int i = 0; i < CHILD_NUM; i++) {
		temp->child[i] = NULL;
	}
	return temp;
}

void insert_trie(TrieTree T, char *p_word) {
	TrieNode *p = T;
	while(*p_word) {
		if(p->child[*p_word - 'a'] == NULL) {
			p->child[*p_word - 'a'] = create_node(*p_word);
		}
		p = p->child[*p_word - 'a'];
		p_word++;
	}
}

int search_trie(TrieTree T, char *p_word) {
	TrieNode *p = T;
	while(p && *p_word) {
		if(p->child[*p_word - 'a'] == NULL) {
			return 0;
		} else {
			p = p->child[*p_word - 'a'];
			p_word++;
		}
	}
	if(p == NULL && *p_word != '\0') {
		return 0;
	} else {
		return 1;
	}
}

void main() {
	TrieTree T = create_node(' ');
	char word[] = "problem";
	char *p = word;
	char bad_word[] = "rob";
	int len = strlen(word);
	int i;
	for(i = 0; i < len; i++) {
		insert_trie(T, p + i);
	}
	if(search_trie(T, bad_word)) {
		printf("this word is bad word!\n");
	} else {
		printf("this word is good word!\n");
	}
}


你可能感兴趣的:(找出文本中存在的坏单词-后缀trie)