AC自动机——1 Trie树(字典树)介绍
2013年10月15日 23:56:45

阅读数:2375

之前,我们介绍了Kmp算法,其实,他就是一种单模式匹配。当要检查一篇文章中是否有某些敏感词,这其实就是多模式匹配的问题。当然你也可以用KMP算法求出,那么它的时间复杂度为O(c*(m+n)),c:为模式串的个数。m:为模式串的长度,n:为正文的长度,那么这个复杂度就不再是线性了,我们学算法就是希望能把要解决的问题优化到极致,这不,AC自动机就派上用场了。

其实AC自动机就是Trie树的一个活用,活用点就是灌输了kmp的思想,只是在AC自动机中,对Trie增加了一个返回的指针,相当于kmp算法中的next值。从而再次把时间复杂度优化到线性的O(N)。

接下来,我们先介绍一下Trie树

保存6个字符串tea,ten,to,in,inn,int的Trie树

Trie树的基本性质可以归纳为:

(1) 根节点不包括字符,除根节点意外每个节点只包含一个字符

(2) 从根节点到某一个节点,路径上经过的字符连接起来,为该节点对应的字符串

(3) 每个节点的所有子节点包含的字符串不相同

当然,Trie树也有一个缺点,如果系统中存在大量字符串且这些字符串基本没有公共前缀,则相应的trie树将非常消耗内存

一下,我们再看Trie树的基本实现

字母树的插入( Insert)、删除(Delete)和查找(Find)都非常简单,用一个一重循环即可,即第i次循环找到前i个字母所对应的子树,然后进行相应的操作。实现这棵字母树,我们用最常见的数组保存(静态开辟内存)即可,当然也可以开动态的指针类型(动态开辟内存)。至于结点对儿子的指向,一般有三种方法:1、列每个结点开一个字母集大小的数组,列应的下标是儿子所表示的字母,内容则是这个儿子列应在大数组上的位置,即标号(易实现,空间要求较大)2、对每个结点挂一个链表,按一定顺序记录每个儿子是谁(空间相对较小,比较费时)3、使用左儿子右兄弟表示法记录这棵树。(空间要求最小,相对费时且不容易写)

  1. //定义节点的子节点数目 26代表26个字母
  2. #define MAX_NUM 26
  3. //定义节点类型,completed意为到从根节点到此节点为一个字符串
  4. enum NODE_TYPE
  5. {
  6. COMPLETED,
  7. UNCOMPLETED
  8. };
  9. //节点数据类型
  10. struct Node
  11. {
  12. enum NODE_TYPE type;
  13. char ch;
  14. struct Node* child[MAX_NUM];
  15. }
  16. struct Node* ROOT;
  17. //创建新节点
  18. struct Node* createNewNode(char ch)
  19. {
  20. struct Node* new_node = (struct Node*) malloc(sizeof(struct Node));
  21. new_node->ch = ch;
  22. new_node->type = UNCOMPLETED;
  23. int i;
  24. for(i=0; i<MAX_NUM; i++)
  25. new_node->child[i] = NULL;
  26. return new_node;
  27. }
  28. //初始化Trie树
  29. void initialization()
  30. {
  31. ROOT = createNewNode('');
  32. }
  33. //
  34. int charToindex(char ch)
  35. {
  36. return ch - 'a';
  37. }
  38. // 查询字符串
  39. int find(const char chars[], int len)
  40. {
  41. struct Node* ptr = ROOT;
  42. int i = 0;
  43. while(i<len)
  44. {
  45. if(ptr->child[charToindex(chars[i])] == NULL)
  46. break;
  47. ptr = ptr->child[charToindex(chars[i])];
  48. i ++;
  49. }
  50. return (i == len) && (ptr->type == COMPLETED);
  51. }
  52. //插入将字符串插入Trie树
  53. void insert(const char chars[], int len)
  54. {
  55. struct Node* ptr = ROOT;
  56. int i;
  57. for(i = 0; i<len; i++)
  58. {
  59. if(ptr->child[charToindex(chars[i])] == NULL)
  60. {
  61. ptr->child[charToindex(chars[i])] == createNewNode(chars[i]);
  62. }
  63. ptr = ptr->child[charToindex[chars[i]]];
  64. }
  65. ptr->type = COMPLETED;
  66. }

Triel树应用

(l)字符串检索
事先将已知的些字符串(字典)的有关信自保存到trie树里,查找另外些未知字符串是否出现过或者出现频率。
举例:
1给出N个单词组成的熟词表,以及篇全用小写英文书写的文章,请你按最早出现的顺序写出所有不在熟词表中的生词。
2给出个词典,其中的单词为不良单词。单词均为小写字母。再给出段文本,文本的每行也自小写字母构成。判断文本中是否含有任何不良单词。例如,若rob是不良单词,那么文本problem含有不良单词。

(2)字符串最长公共前缀
Trie树利用多个字符串的公共前缀来节省存储空间,反之,当我们把大量字符串存储到棵trie树上时,我们可以快速得到某些字符串的公共前缀。
举例:
1给出N个小写英文字母串,以及Q个询问,即询问某两个串的最长公共前缀的长度是多少
解决方案:首先对所有的串建互其对应的字母树。此时发现,对于两个串的最长公共前缀的长度即它们所在结点的公共祖先个数,于是,问题就转化为了离线(Offline)的最近公共祖先(L—t Comon An…tor,简称LCA)问题
而最近公共祖先问题同样是个经典问题.可以用下面几种方法:
1)利用并查集(Disioint Set),可以采用采用经典的Tarian算法,
2)求出字母树的殴拉序列(Eul er  Sequence)后,就可以转为经典的最小值查询(RanZeMinimum Querr,简称ⅫO)问题了,
(关于并查集,T arjar薄法,Ⅻ。问题,网上有很多资料。)

(3)排序
Trie树是棵多叉树,只要先序遍历整棵树,输出相应的字符串便是按字典序排序的结果。
举例:
给你N个互不相同的仅由一个单词构成的英文名,让你将它们按字典序从小到大排序输出。

(4)作为其他数据结构和算法的辅助结构
如后缀树,AC自动机等

同时,由于Trie树的空间复杂度是26^n级别,非常庞大,可用双数组改善

AC自动机——1 Trie树(字典树)介绍的更多相关文章

  1. 剑指Offer——Trie树(字典树)

    剑指Offer--Trie树(字典树) Trie树 Trie树,即字典树,又称单词查找树或键树,是一种树形结构,是一种的单词.对于每一个单词,我们要判断他出没出现过,如果出现了,求第一次出现在第几个位 ...

  2. Trie(字典树)

    没时间整理了,老吕又讲课了@ @ 概念 Trie即字典树,又称单词查找树或键树,是一种树形结构,是一种哈希树的变种,典型应用是统计和排序大量的字符串(不限于字符串) Trie字典树主要用于存储字符串, ...

  3. POJ 2778 DNA Sequence ( AC自动机、Trie图、矩阵快速幂、DP )

    题意 : 给出一些病毒串,问你由ATGC构成的长度为 n 且不包含这些病毒串的个数有多少个 分析 : 这题搞了我真特么久啊,首先你需要知道的前置技能包括 AC自动机.构建Trie图.矩阵快速幂,其中矩 ...

  4. 9-11-Trie树/字典树/前缀树-查找-第9章-《数据结构》课本源码-严蔚敏吴伟民版

    课本源码部分 第9章  查找 - Trie树/字典树/前缀树(键树) ——<数据结构>-严蔚敏.吴伟民版        源码使用说明  链接☛☛☛ <数据结构-C语言版>(严蔚 ...

  5. Trie树(字典树)的介绍及Java实现

    简介 Trie树,又称为前缀树或字典树,是一种有序树,用于保存关联数组,其中的键通常是字符串.与二叉查找树不同,键不是直接保存在节点中,而是由节点在树中的位置决定.一个节点的所有子孙都有相同的前缀,也 ...

  6. Trie(前缀树/字典树)及其应用

    Trie,又经常叫前缀树,字典树等等.它有很多变种,如后缀树,Radix Tree/Trie,PATRICIA tree,以及bitwise版本的crit-bit tree.当然很多名字的意义其实有交 ...

  7. Trie树 字典树-学习笔记

    字符串--蒟蒻永远的阴影 对于字符串匹配 KMP很好的解决了以一个文本串匹配一个模板串的问题 但如果模板串有多个呢 这是KMP不再适用 我们引入一个新的数据结构--字典树 (当然又有像AC自动机这样更 ...

  8. [LintCode] Implement Trie 实现字典树

    Implement a trie with insert, search, and startsWith methods. Have you met this question in a real i ...

  9. Trie树|字典树(字符串排序)

    有时,我们会碰到对字符串的排序,若采用一些经典的排序算法,则时间复杂度一般为O(n*lgn),但若采用Trie树,则时间复杂度仅为O(n). Trie树又名字典树,从字面意思即可理解,这种树的结构像英 ...

随机推荐

  1. BVLC CaffeNet可视化及类别预测

    一.介绍 bvlc_reference_caffenet网络模型是由AlexNet的网络模型改写的,输入图片尺寸大小为227x227x3,输出的为该图片对应1000个分类的概率值. 介绍参考:caff ...

  2. 装完Centos7提示Initial setup of CentOS Linux 7 (core)

    在用U盘装完CentOS后,重新开机启动后显示: Initial setup of CentOS Linux 7 (core) 1) [x] Creat user 2) [!] License inf ...

  3. react学习笔记1一基础知识

    1.React 是一个用于构建用户界面的 JAVASCRIPT 库2.React 特点: a.声明式的设计 b.采用虚拟dom,最大限度的减少dom操作 C.组件化,可以复用 D.单向响应的数据流,减 ...

  4. 【mysql】批量更新数据

    概述 批量更新mysql数据表数据,上网搜索基本都会说4~5方法,本人使用的更新方式为: INSERT ... ON DUPLICATE KEY UPDATE Syntax 可参见官方网站:inser ...

  5. linux git 保存用户名和密码

    一.通过文件方式 1.在~/下, touch创建文件 .git-credentials, 用vim编辑此文件,输入内容格式: touch .git-credentials vim .git-crede ...

  6. CSS之checkbox&radio&textarea&select

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. windows异常事件对应的ID

    转载地址: Windows 2008 R2查看异常关机或开机事件ID https://blog.csdn.net/hejun1218/article/details/81059327

  8. eclipse各版本及下载

    附:Eclipse各个版本简介(http://zh.wikipedia.org/wiki/Eclipse) eclipse下载地址: https://www.eclipse.org/官网--右上角的I ...

  9. 涂抹mysql笔记-数据备份和恢复

    <>物理备份和逻辑备份<>联机备份和脱机备份<>本地备份和远程备份<>完整备份和增量备份<>完整恢复和增量恢复<>复制表相关文件 ...

  10. Vue自学笔记--项目的创建

    一.项目的创建 1.必须要安装nodejs    2.搭建vue的开发环境 ,安装vue的脚手架工具   官方命令行工具        npm install --global vue-cli  /  ...