字典树

[原创] Trie树 php 实现敏感词过滤

女生的网名这么多〃 提交于 2020-02-02 06:33:44
目录 背景 简介 存储结构 PHP 其他语言 字符串分割 示例代码 php 优化 缓存字典树 常驻服务 参考文章 背景 项目中需要过滤用户发送的聊天文本, 由于敏感词有将近2W条, 如果用 str_replace 来处理会炸掉的. 网上了解了一下, 在性能要求不高的情况下, 可以自行构造 Trie树(字典树), 这就是本文的由来. 简介 Trie树是一种搜索树, 也叫字典树、单词查找树. DFA可以理解为DFA(Deterministic Finite Automaton), 即 这里借用一张图来解释Trie树的结构: Trie可以理解为确定有限状态自动机,即DFA。在Trie树中,每个节点表示一个状态,每条边表示一个字符,从根节点到叶子节点经过的边即表示一个词条。查找一个词条最多耗费的时间只受词条长度影响,因此Trie的查找性能是很高的,跟哈希算法的性能相当。 上面实际保存了 abcd abd b bcd efg hij 特点: 所有词条的公共前缀只存储一份 只需遍历一次待检测文本 查找消耗时间只跟待检测文本长度有关, 跟字典大小无关 存储结构 PHP 在PHP中, 可以很方便地使用数组来存储树形结构, 以以下敏感词字典为例: 大傻子 大傻 傻子 ↑ 内容纯粹是为了举例...游戏聊天日常屏蔽内容 则存储结构为 { "大": { "傻": { "end": true "子": {

Trie(字典树)的侃侃

烂漫一生 提交于 2020-01-30 00:04:52
Trie是什么 ? 字典树 : 见名知意(在树上进行查询)。 跟字典相关的必定与查询有密切的关系, 查询就需要一定的媒介作为支撑,树就为这种查询提供支撑。 Trie做什么 ? 实现字符串快速检索的多叉树结构。 常见的字符串转化:小写字母或者大写字母组成的字符串,数字组成的字符串,01编码组成的字符串。 Trie有什么 ? Trie 的每个节点都拥有若干个字符指针,就是说每个节点有多个子节点,通俗一点就是相当于古代 的大少爷可以有多个妻子。 Trie干什么 ? 1、插入(将一个字符串插入到字典树上) 2、检索(检索一个字符串 S 在Trie 上是否存在) 侃了这么多,看看这货到底是个啥 ? 假设有单词 : cab , cef , da 这样三个单词,那么这样三个单词组成的图是什么样的呢 ? 看下图 : (通常还要在末尾进行标记一下,表示到字符串的末尾) 怎么实现这个玩意呢 ? 插入 : 像每个单词拼写一样,单词的开头就相当于是我们的根,从根节点出发,向儿子节点前进。 在向下走的过程中,看有没有当前这个字符的节点,如果有这个节点,就顺着这个节点继续 往下走,如果没有这个节点,就在这个节点之下再创建一个节点。 拿一个例子来说: 比如上图的 cab 和 cef, 先插入第一个字符串,从根节点出发,第一个字符是 c,我们发 现没有这个字符的节点,所以创建一个节点,将指针节点进行指向

# 前缀统计~[字典树]

亡梦爱人 提交于 2020-01-25 16:26:24
前缀统计~[字典树] 传送门 题意 给出N个字符串,进行M次询问,每次给出一个字符串,询问N个字符串中有多少个是它的前缀。 思路 字典树Trie入门题。 字典树最典型的应用就是用来存储字符串。 其中每个节点下有26个子节点(对应26个字母),根据新建节点的顺序使用idx为节点编号,根节点和空节点编号都为0,每个叶节点维护一个cnt,标记以这个叶节点结尾的字符串有几个。 使用这种存储方式可以很容易查找一个字符串是否存在,以及出现过几次等等。 Code: #include <bits/stdc++.h> using namespace std; #define fre freopen("data.in","r",stdin); #define ms(a) memset((a),0,sizeof(a)) #define go(i,a,b) for(register int (i)=(a);(i)<(b);++(i)) #define rep(i,a,b) for(register int (i)=(a);(i)<=(b);++(i)) #define sf(x) scanf("%d",&(x)) #define reg register typedef long long LL; const int inf=(0x3f3f3f3f); const int maxn=1e6+5; int

字典树

三世轮回 提交于 2020-01-24 05:29:08
又称 单词查找树 , Trie树 ,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来节约存储空间,最大限度地减少无谓的字符串比较,查询效率比哈希表高。 字典树与字典很相似,当你要查一个单词是不是在字典树中,首先看单词的第一个字母是不是在字典的第一层,如果不在,说明字典树里没有该单词,如果在就在该字母的孩子节点里找是不是有单词的第二个字母,没有说明没有该单词,有的话用同样的方法继续查找.字典树不仅可以用来储存字母,也可以储存数字等其它数据。 Trie的数据结构定义: #define MAX 26 typedef struct Trie { Trie * next[MAX]; int v; // 根据需要变化 }; Trie * root; next是表示每层有多少种类的数,如果只是小写字母,则26即可,若改为大小写字母,则是52,若再加上数字,则是62了,这里根据题意来确定。 v可以表示一个字典树到此有多少相同前缀的数目,这里根据需要应当学会自由变化。 Trie的查找(最主要的操作): (1) 每次从根结点开始一次搜索; (2) 取得要查找关键词的第一个字母,并根据该字母选择对应的子树并转到该子树继续进行检索;   (3) 在相应的子树上

字典树(讲解+模版)

安稳与你 提交于 2020-01-22 20:41:07
又称 单词查找树 , Trie树 ,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来节约存储空间,最大限度地减少无谓的字符串比较,查询效率比哈希表高。 字典树与字典很相似,当你要查一个单词是不是在字典树中,首先看单词的第一个字母是不是在字典的第一层,如果不在,说明字典树里没有该单词,如果在就在该字母的孩子节点里找是不是有单词的第二个字母,没有说明没有该单词,有的话用同样的方法继续查找.字典树不仅可以用来储存字母,也可以储存数字等其它数据。 Trie的数据结构定义: #define MAX 26 typedef struct Trie { Trie * next[MAX]; int v; // 根据需要变化 }; Trie * root; next是表示每层有多少种类的数,如果只是小写字母,则26即可,若改为大小写字母,则是52,若再加上数字,则是62了,这里根据题意来确定。 v可以表示一个字典树到此有多少相同前缀的数目,这里根据需要应当学会自由变化。 Trie的查找(最主要的操作): (1) 每次从根结点开始一次搜索; (2) 取得要查找关键词的第一个字母,并根据该字母选择对应的子树并转到该子树继续进行检索;   (3) 在相应的子树上

HihoCoder 1289 403 Forbidden 字典树

烂漫一生 提交于 2020-01-22 01:29:12
题目链接(vj):https://cn.vjudge.net/problem/HihoCoder-1289 题目 题目大意:n条ip/mask.输入规则为 allow | deny address 或者 allow | deny address/mask ,比如 allow 1.2.3.4/30 (allow可以访问), deny 1.1.1.1 (deny不可以访问)。再输入一个ip进行访问要求,有几种对应方式: 和无mask的ip相同,那么能否访问取决于那个op是allow还是deny 和有mask的ip对应,这种方式是指ip的32位的2进制的表示方式的前mask位一样,那么就算对应。 10000000 01111111 0000,0100 01100100 (128.127.4.100) 10000000 01111111 0000,1000 01111101 (128.127.8.125) 当mask = 20,因为前20位相同,所以可以匹配 如果找不到对应的ip,那么就是可以访问。 思路 因为第一次做字典树,所以大部分看的别人代码。模板字典树用数组存储(参考qy模板)。 struct Trie { int cnt , root , go [ maxL ] [ 2 ] , id [ maxL ] , tag [ maxL ] ; int create ( ) { ++

字典树Trie学习笔记

自古美人都是妖i 提交于 2020-01-21 17:04:29
一个 简单的 问题 问题:有 n n n 个由小写字母组成的字符串( n ≤ 1 0 5 n\le 10^5 n ≤ 1 0 5 ,字符串长度 L ≤ 20 L\le 20 L ≤ 2 0 )。有 Q Q Q 组询问( Q ≤ 1 0 5 Q\le10^5 Q ≤ 1 0 5 ),每次给出一个字符串,你需要回答这个字符串在给出的 n n n 个字符串中是否出现。 方法一:暴力,每个询问和前面大莉比较,时间复杂度 O ( Q n L ) O(QnL) O ( Q n L ) 。 方法二:把 n n n 个字符串存入map中,每个询问在map中查询。不太清楚map复杂度怎么算,目测总时间复杂度 O ( L n l o g n + L Q l o g n ) O(Lnlogn+LQlogn) O ( L n l o g n + L Q l o g n ) 。 方法三:蛤希,时间复杂度 O ( L n + L Q ) O(Ln+LQ) O ( L n + L Q ) ,但可能会有蛤希冲突。 方法四:Trie。 Trie树基本内容 建立和查询方法 在Trie树中,我们用边来表示每个字符,点表示字符串结束的位置。 让每个点所对应的字符串为根节点到这个点的路径所对应的字符按顺序连接得到的字符串。 举个例子:现在有四个字符串ypy,ygy,yxc,mhy。那么珂以根据规则建立Trie树:

Trie--字典树

允我心安 提交于 2020-01-20 21:26:36
Trie--字典树 在计算机科学中, trie ,又称 前缀树 ,是一种有序树,用于保存关联数组,其中的键通常是字符串。与二叉查找树不同,键不是直接保存在节点中,而是由节点在树中的位置决定。一个节点的所有子孙都有相同的前缀,也就是这个节点对应的字符串,而根节点对应空字符串。一般情况下,不是所有的节点都有对应的值,只有叶子节点和部分内部节点所对应的键才有相关的值。 Trie 这个术语来自于 re trie val。根据词源学,trie 的发明者 Edward Fredkin 把它读作 / ˈ t r iː / "tree"。但是,其他作者把它读作 / ˈ t r aɪ / "try"。 在图示中,键标注在节点中,值标注在节点之下。每一个完整的英文单词对应一个特定的整数。Trie 可以看作是一个 确定有限状态自动机 ,尽管边上的符号一般是隐含在分支的顺序中的。 键不需要被显式地保存在节点中。图示中标注出完整的单词,只是为了演示 trie 的原理。 trie 中的 键通常是字符串 ,但也可以是其它的结构。trie 的算法可以很容易地修改为处理其它结构的有序序列,比如一串数字或者形状的排列。比如, bitwise trie 中的键是一串位元,可以用于表示整数或者内存地 Trie树 是一种 哈希树的变种 ,典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串)

巧用字典树算法,轻松实现日志实时聚类分析

隐身守侯 提交于 2020-01-17 11:46:02
by 田富龙 日志分析对于企业运维来说尤为重要,运维人员如不能实时了解服务器的安全状况,会给企业造成难以估计的损失。对日志进行分析,不仅可以了解到软、硬件设备的运行状况,还可以了解到报错日志的源头、服务器上正在发生的安全事件,判断错误是由应用引发的还是系统本身引起的,从而及时进行补救,以提高企业软、硬件设备的高可用性。 然而,随着服务器数量逐渐增加,日志数据也与日俱增,面对这种境况,利用传统的方式对日志进行分析,显然已经不能满足企业的要求。此时,基于AI技术的日志分析方式就显得尤为重要。 本文提出的实时日志聚类算法,通过提取日志模板方式,能够有效帮助运维人员进行诊断以及定位问题,提高解决问题的效率,从而起到事半功倍的效果。 在这里,我们将介绍实时日志聚类算法中用到的子算法–字典树,它能极大提升日志聚类算法的效率,使实时日志聚类算法能够在极短的时间内,从海量的日志信息中提取出日志模板。 字典树(Trie),又称前缀树,是哈希树(Hash Tree)的一种变种。它的核心思想是以空间换时间,常常用于统计、排序和保存大量的字符串(但不仅限于字符串)。在Trie的每个 Node中保存一个字符以及该节点的所有子节点,并且每个Node中带有一个标志位,用来标识由根节点出发到该节点为止是否能组成一个完整的字符串。 通常规定根节点对应空字符串,由于Trie是一种有序树结构

字典树 + 并查集 + 滑动窗口 + 优先队列 demo

拜拜、爱过 提交于 2020-01-16 09:57:25
统计一段时间内(500)单词出现的频率 单词最长为10 void init(); 初始化函数 void searchWord(int tsec, char str[], int num); 在tsec时刻,搜索了某一个单词str, 它的频率是num void banWord(int tsec, char str[]); 在tsec时刻,ban到了单词str,在以后的rank中不会再出现str void mergeWords(int tsec, char str1[], char str2[]); 在tsec时刻,合并单词,str2不在出现在rank中,且str2的频率都计算到str1中,相当于父子关系 int getRank10(int, char[][MAX_WORD_LEN + 1]); 在tsec时刻,返回该时刻以及前500s内的所有单词出现频率最高的单词。 # define MAX_WORD_LEN 10 # define USEFUL 0 # define BAN 1 # define MERGED 2 static void mstrcpy ( char dest [ ] , const char src [ ] ) { int i = 0 ; while ( ( dest [ i ] = src [ i ] ) != '\0' ) i ++ ; } static