Evanyou Blog 彩带

Trie树(字典树)

  字典树,顾名思义,是用来进行字符串查找的一种数据结构。试想一下,如果给你一堆字符串,问你其中每个字符串是否出现过,那怎么办?很容易,map,短小精悍。那如果给你一堆单词,再丢给你另一堆字符串,问你字符串中出现过哪些单词构成的前缀呢?

  这里就可以用到trie树这种结构了。

  首先假设所有字符串均为小写,给你以下几个单词:

  cat,cash,app,apple,aply,ok

  那么可以构成下面这样一个trie树:

  

  因此可得出:

  1,字典树用边表示字符(其实也可以用点表示)

  2,前缀相同的单词共用前缀结点,因此一个结点最多有26个子节点

  3,根节点为空,这样是为了方便查找,后面会讲

  4,一个单词结束后用一个特殊字符表示结束(用结构体的话也可以放一个bool变量),根节点到每一个标记就表示一个单词

  那么下面讲讲trie树的基本操作:

  1,插入insert

  很简单,从根节点开始遍历,如果有相同的前缀,那就直接沿着前缀向下继续遍历;如果找不到相同前缀,就插入新的字符,一直到单词结束。

  那既然如此就涉及到结点的编号,trie树中每个结点都有两种编号,一种是按插入顺序编号,另一种是按字母编号,下图中,红色标号是第一种,紫色是第二种,可以看出,按第一种编号的话,相同字母可能有不同的编号,按第二种编号,相同字母的标号相同,并只有26种,用s表示该字符,即s-'a';

  

 

  

  插入代码如下:

inline void insert()
{
  int len=strlen(s);
  int root=0;
  for(int i=0;i<len;i++){
    int id=s[i]-'a';
    if(!t[root][id])
      t[root][id]=++tot;
    root=t[root][id];
  }
}

  2,查找search

  查找一个单词也很容易,从根节点开始,如果有相同前缀就继续向下遍历,直到完整地查找完整个单词或者发现单词不存在这棵树上为止

  代码:

  

inline void search()
{
  int len=strlen(s);
  int root=0,k=0;
  while(1){
    int id=s[k]-'a';
    if(!t[root][id])
      break;
    root=t[root][id];
    k++;
    if(k==len)break;
  }
  if(k==len)printf("YES\n");
  else printf("NO\n");
}

  当然这两种也只是最基本的操作,至于其他操作我这里就不多讲了(懒癌晚期),网上大佬们的博客里都讲的很清楚了,这里再放一个模板题的代码:

 

//It is made by HolseLee on 6th Feb 2018
//Codevs P4189
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
int n,m,tot;
char s[11];
int t[2000020][26];
inline void insert()
{
  int len=strlen(s);
  int root=0;
  for(int i=0;i<len;i++){
    int id=s[i]-'a';
    if(!t[root][id])
      t[root][id]=++tot;
    root=t[root][id];
  }
}
inline void check()
{
  int len=strlen(s);
  int root=0,k=0;
  while(1){
    int id=s[k]-'a';
    if(!t[root][id])
      break;
    root=t[root][id];
    k++;
    if(k==len)break;
  }
  if(k==len)printf("YES\n");
  else printf("NO\n");
}
void ready()
{
  scanf("%d",&n);
  for(int i=1;i<=n;i++){
    scanf("%s",s);
    insert();}
}
void work()
{
  scanf("%d",&m);
  for(int i=1;i<=m;i++){
    scanf("%s",s);
    check();}
}
int main()
{
  ready();
  work();
  return 0;
}

 

 

 

 

posted @ 2018-02-06 21:02  HolseLee  阅读(388)  评论(0编辑  收藏  举报