Trie树

来源:互联网 发布:少儿编程培训班 广州 编辑:程序博客网 时间:2024/06/10 04:11

Trie树

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级别的。所以为了节省空间。我们用动态链表,或者用数组来模拟动态。空间的花费,不会超过单词数×单词长度。

由字母a~z所组成的字符串的一个集合中,各个字符的长度之和为n。设计一个O(n)时间的算法,将这个集合中所有字符串依字典进行排序。注意,这里可能存在非常长的字符串。

#include <stdio.h>

#include <malloc.h>

 

typedef struct tire

{

  struct tire *next[26];

  char date;

  int cnt;

}*_tire;

void init_tire(_tire root, char *string)

{

   _tire s;

   s=root;

   while(*string!='\0')

    {

      if(s->next[*string - 'a']==NULL)

      {

         s->next[*string - 'a'] = (_tire)malloc(sizeof(struct tire));

         (s->next[*string - 'a'])->date = *string;

         s = s->next[*string - 'a'];

         for(int i=0;i<26;i++)

         {

              s->next[i] = NULL;

         }

      }

      else

      {

         s = s->next[*string - 'a'];

      }

      string++;

    }

   s->cnt=1;

}

 

void print(_tire root, char *s, int i)

{

   int j;

   s[i] = root->date;

 

   if(root->cnt==1)

    {

       s[i+1] = 0;

       puts(s);

    }

  

   for(j=0;j<26;j++)

    {

       if(root->next[j]!=NULL)

       {

          print(root->next[j],s,i+1);

       }

    }

}

int main()

{

   _tire root;

   int m,i;

   char s[265];

  

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

   puts("输入字符串个数:");

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

    {

      root->next[i]=NULL;

    }

   scanf("%d",&m);

   getchar();

   while(m--)

    {

      gets(s);

      init_tire(root,s);

    }

   puts("\n依字典排序后:");

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

    {

      if(root->next[i] != NULL)

      {

         print(root->next[i],s,0);

      }

    }

   return 0;

}

 

原创粉丝点击