zoukankan      html  css  js  c++  java
  • Evanyou Blog 彩带

      字典树,顾名思义,是用来进行字符串查找的一种数据结构。试想一下,如果给你一堆字符串,问你其中每个字符串是否出现过,那怎么办?很容易,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
    ");
      else printf("NO
    ");
    }

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

     

    //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
    ");
      else printf("NO
    ");
    }
    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;
    }
  • 相关阅读:
    实反对称矩阵正则化
    小矩阵相乘效率对比:lapack, cblas, 手写函数
    python实现: VMC做一维谐振子
    一个简单矩阵的本征值问题
    python画能级图
    广义相对论笔记
    PVPC kb3g pn/upn Ti44 LAP 脚本
    自组织临界现象:沙堆模型
    c#备份MySQL数据库 转载 from
    vs2010 新特性 from
  • 原文地址:https://www.cnblogs.com/cytus/p/8424216.html
Copyright © 2011-2022 走看看