trie字典树模板浅析

什么是trie?

百度百科

又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。

trie有什么用处?

①进行快速的查找字符串是否存在

②进行快速的字符串的前缀和的相关的性质的查询

如何实现trie?

导言

trie是靠二维数组进行存储的,其中trie[a][b]=c,指的是a的第b个孩子的编号是c。特别的trie是用边来存储字符而并不是节点!编号代表的是a-z的26个字母中的第几个字母所以编号是从0-25。

百度百科的图片

①insert函数

insert函数代表着插入操作。如何实现呢?

(1)把需要插入的string拆分成一个又一个的单个的字符进行操作。并且把rt初始化为0

int rt=0;
for(int i=0;i<a.size();i++)
{
 //....
}

(2)计算id编号(注意这个地方是-'a'不是-'0')

int id=a[i]-'a';

(3)循环判断当前的父节点是不是存在一条以id编号的边,如果不存在那么,添加一个这样的边并且把子节点赋予一个编号

if(!trie[rt][id])
    trie[rt][id]=++tot;

(4)将rt层层递进

rt=trie[rt][id];

insert函数完整代码

void insert(string a)
{
  int rt=0;
  for(int i=0;i<a.size();i++)
  {
    int id=a[i]-'a';
    if(!trie[rt][id])
    trie[rt][id]=++tot;
    rt=trie[rt][id];
  }
}

②search函数

search函数代表着查询的操作,这里我们查询当前前缀是不是在树中,当然trie可以做很多别的操作,结合insert函数,如何实现?

(1)(2)同insert函数

  int rt=0;
  for(int i=0;i<a.size();i++)
  {
    int id=a[i]-'a';
    //.....
    }

(3)查询相应的编号的边是不是这个父节点的儿子,如果不是那么返回0

if(!trie[rt][id])
    return 0;

(4)层层递进同insert

rt=trie[rt][id];

(5)如果这个字符串能安全的走出循环,那么就返回1,说明这个前缀是存在的

search函数完整代码

int search(string a)
{
  int rt=0;
  for(int i=0;i<a.size();i++)
  {
    int id=a[i]-'a';
    if(!trie[rt][id])
    return 0;
    rt=trie[rt][id];
  }
  return 1;
}

trie模板完整代码(注意此处的map效率过慢,应该直接开数组为妙)

#include <bits/stdc++.h>
using namespace std;
map<int,map<int,int> > trie;
map<int,int> sum;
int tot;
void insert(string a)
{
  int rt=0;
  for(int i=0;i<a.size();i++)
  {
    int id=a[i]-'a';
    if(!trie[rt][id])
    trie[rt][id]=++tot;
    rt=trie[rt][id];
  }
}
int search(string a)
{
  int rt=0;
  for(int i=0;i<a.size();i++)
  {
    int id=a[i]-'a';
    if(!trie[rt][id])
    return 0;
    rt=trie[rt][id];
  }
  return 1;
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int n,m;
    cin>>n>>m;
    for(int i=0;i<n;i++)
    {
      string a;
      cin>>a;
      insert(a);
    }
    for(int i=0;i<m;i++)
    {
      string a;
      cin>>a;
      if(search(a))
      cout<<"YES
";
      else
      cout<<"NO
";
    }
}

拓展

①查询相应前缀所包含的字符串的数量(hdu 1251 统计难题)

只需要在insert函数中设定一个sum数组,保存每个节点遍历过的次数,即sum[trie[rt][id]]++,然后在search函数中寻找到字符串最后的节点返回sum[rt]即可。只要中间出现没有在树中的字符直接return0

②查询相应的单词是否在树中

只需要在insert函数中设置一个记录词尾的数组即可,然后search函数中找到最后如果这个词尾存在的话那么就是存在否则就是不存在

原文地址:https://www.cnblogs.com/baccano-acmer/p/9985108.html