现在的位置: 首页 > 综合 > 正文

Tire字典树(zz)

2013年03月06日 ⁄ 综合 ⁄ 共 2202字 ⁄ 字号 评论关闭

最近接触的字典算法中就用到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;
}

查找和插入可以用同一函数实现,改天研究哈嗯哪

抱歉!评论已关闭.