您的位置:首页 > 其它

Tire字典树(zz)

2009-10-31 20:41 225 查看
最近接触的字典算法中就用到Tire树,老听他们在说什么双Trie树,今天搜了下Tire树。转载一篇。

Trie树就是字符树,其核心思想就是空间换时间。
举个简单的例子。
给你100000个长度不超过10的单词。对于每一个单词,我们要判断他出没出现过,如果出现了,第一次出现第几个位置。
这题当然可以用hash来,但是我要介绍的是trie树。在某些方面它的用途更大。比如说对于某一个单词,我要询问它的前缀是否出现过。这样hash就不好搞了,而用trie还是很简单。
现在回到例子中,如果我们用最傻的方法,对于每一个单词,我们都要去查找它前面的单词中是否
有它。那么这个算法的复杂度就是O(n^2)。显然对于100000的范围难以接受。现在我们换个思路想。假设我要查询的单词是abcd,那么在他前面的
单词中,以b,c,d,f之类开头的我显然不必考虑。而只要找以a开头的中是否存在abcd就可以了。同样的,在以a开头中的单词中,我们只要考虑以b作
为第二个字母的……这样一个树的模型就渐渐清晰了……
假设有b,abc,abd,bcd,abcd,efg,hii这6个单词,我们构建的树就是这样的。



对于每一个节点,从根遍历到他的过程就是一个单词,如果这个节点被标记为红色,就表示这个单词存在,否则不存在。
那么,对于一个单词,我只要顺着他从跟走到对应的节点,再看这个节点是否被标记为红色就可以知道它是否出现过了。把这个节点标记为红色,就相当于插入了这个单词。
这样一来我们询问和插入可以一起完成,所用时间仅仅为单词长度,在这一个样例,便是10。
我们可以看到,trie树每一层的节点数是26^i级别的。所以为了节省空间。我们用动态链表,或者用数组来模拟动态。空间的花费,不会超过单词数×单词长度。
看个例子把,也是转载的,继续学习!
/*

* 字典树
摸模版代码。

* 高效的字符串查找数据结构,所须查找的长度和

* 字符串的数量没有关系, 只和待查的字符串的长度有关。

* 而一般的字字符串查找的时间复杂度为常数级别。

*/

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#define MAX 'z' - 'a' + 1

#define SLEN 11

struct tire {

struct tire *next[MAX];

char s[SLEN];

int isword;

} *root;

struct tire *init(void)
{

struct tire *root = (struct tire *)malloc(sizeof(struct tire));

int i;

for (i = 0; i < MAX; i++)
root->next[i] = NULL;

root->isword = 0;

return root;

}

void insert(char path[], char s[]) {

struct tire *t, *p = root;

int i, j, n = strlen(path);

for (i = 0; i < n; i++) {

if (p->next[path[i] - 'a'] == NULL) {

t = (struct tire *)malloc(sizeof(struct tire));

for (j = 0; j < MAX; j++) t->next[j] = NULL;

t->isword = 0;

p->next[path[i] - 'a'] = t;

}

p = p->next[path[i] - 'a'];

}

p->isword = 1;

strcpy(p->s, s);

}

char *find(char path[], int delflag) {

struct tire *p = root;

int i, n = strlen(path);

i = 0;

while (p && path[i]) p = p->next[path[i++] - 'a'];

if (p && p->isword) {

p->isword = delflag;

return p->s;

}

return NULL;

}

void del(struct tire *root) {

int i;

if (!root) return;

for (i = 0; i < MAX; i++)

if (root->next[i]) del(root->next[i]);

free(root->next[i]);

}

int main(void) {

char line[256], s1[256], s2[256];

char *s;

root = init();

while (gets(line)) {

if (sscanf(line, "%s %s", s1, s2) != 2) break;

insert(s2, s1);

}

while (scanf("%s", s1) == 1) {

s = find(s1, 1);

if (s == NULL) printf("eh/n");

else printf("%s/n", s);

}

return 0;

}

查找和插入可以用同一函数实现,改天研究哈嗯哪
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: