Trie 字典树

本文详细介绍了字典树(Trie),一种用于高效存储和检索字符串集合的数据结构。文章解释了字典树的基本概念,包括其节点结构、初始化、插入和查询操作,并提供了具体的代码实现。

简介

   字典树,也称Trie或字母树,指的是某个字符集合对应的有根数。树的每条边上恰好对应一个字符,每个顶点代表从根到该结点的路径所对应的字符串(将所有经过的边上的字符按顺序连接起来)。有时我们也称Trie上的边为转移,顶点为状态。

                                                          

    上图展示了在一棵空Trie中依次插入abcd abd bcd efg hi后的形态,实心代表单词的末尾结点。

    实际上,任意一个线结点所代表的字符串,都是实际字符串集合中某些串的前缀。特别的,根节点代表空串。 

 操作实现

  1.初始化

    一棵空Trie仅包含一个根结点,该点的字符指针均指向空

Trie的结点信息可以用几个数组存储,以下代码中ch[u][i]表示结点 u的i字符指针指向的结点,若数组的值为0表示没有这个子节点。

int ch[N][Z] //Z为字符集大小
bool bo[N] //若bo=true则表示从根到该节点经过的边上的字母组成的字符串是实际字符串集合中的元素

2.插入

  当需要插入一个字符串S时,我们令一个指针P起初指向根节点。然后,依次扫描S中的每个字符c:

  (1) 若指针P 的c字符指针指向一个已存在的结点Q,则令P=Q。

  (2) 若指针P的c字符指针指向空,则新建一个结点Q,令P的c字符指针指向Q,然后令P=Q。

  (3) 当S中的字符扫描完毕时,在当前结点指针P上标记它是一个字符串的末尾。

  现在要对一个字符集为小写英文字母的Trie插入一个字符串S:

  

int tot=1;
void insert(char *s) //char *s表示一个字符数组
{
   int len=strlen(s);
   int u=1;  //1为根结点
   for(int i=0;i<len;i++)
   { 
      int c=s[i]-'a';
      if(!ch[u][c])
       ch[u][c]=++tot; //若不存在这条边则要新建一个结点与转移边
      u=ch[u][c];
   }
  bo[u]=true; //在串的结尾将bo赋值,表示它代表一个实际字符集合中的元素
}

3.查询

 当需要查询一个字符串S在Trie中是否存在时,我们令一个指针P起初指向根结点,然后依次扫描S中的每个字符c:

(1) 若指针P的c字符指针指向空,说明S没有没插入Trie,结束查询

(2) 若指针P的c字符指针指向一个已经存在的结点Q,则令P=Q。

(3) 若指针S中的字符扫描完毕时,若当前结点P被标记为一个字符串的末尾,则说明S在Trie中已经存在,否则说明S没有被插入过Trie

查询一个字符串S是否是给定字符串集合中某个串的前缀:

bool find(char *s)
{
   int len=strlen(s);
   int u=1;
   for(int i=0;i<len;i++)
   {
      int c=s[i]-'a';
      if(!ch[u][c]) return false;
      u=ch[u][c];
   }
 return true;
}

 

### 使用Trie字典树进行敏感词检测的实现方法 #### 背景介绍 Trie字典树是一种高效的数据结构,广泛应用于字符串处理领域。它通过共享公共前缀的方式减少了存储空间和查询时间,在敏感词检测场景下表现尤为突出[^1]。 #### 数据结构设计 Trie的核心在于其节点的设计。每个节点通常包含以下几个部分: - **字符**:当前节点所代表的字符。 - **子节点集合**:指向下一个可能的字符节点。 - **结束标志位 (isEnd)**:用于标记某个路径是否构成了完整的敏感词[^2]。 以下是Trie节点的一个简单定义: ```java class TrieNode { private boolean isEnd; private Map<Character, TrieNode> children; public TrieNode() { this.children = new HashMap<>(); this.isEnd = false; } public boolean isEnd() { return isEnd; } public void setEnd(boolean end) { isEnd = end; } public Map<Character, TrieNode> getChildren() { return children; } } ``` #### 插入敏感词 为了构建一棵能够完成敏感词检测的Trie,首先需要将所有的敏感词插入到中。每插入一个新词时,按照字母顺序逐层创建节点并更新`isEnd`属性以标记完整词语的位置[^3]。 示例代码如下所示: ```java public class Trie { private final TrieNode root; public Trie() { root = new TrieNode(); } // 向Trie中添加一个新的敏感词 public void addWord(String word) { TrieNode current = root; for (char c : word.toCharArray()) { if (!current.getChildren().containsKey(c)) { current.getChildren().put(c, new TrieNode()); } current = current.getChildren().get(c); } current.setEnd(true); // 设置最后一个节点为终止状态 } } ``` #### 进行敏感词过滤 当完成了所有敏感词的初始化之后,就可以基于这棵Trie来进行实际的文字审查工作了。具体做法是从输入文本的第一位开始逐步向下匹配直到找到整个句子或者遇到未记录下来的分支为止[^2]。 下面给出了一段Java程序片段展示如何替换掉原文中的不当表述部分: ```java public String filter(String text) { StringBuilder sb = new StringBuilder(); int length = text.length(); for(int i=0;i<length;){ int j=i; TrieNode node=root; while(j<length && node!=null){ char ch=text.charAt(j); node=node.getChildren().get(ch); if(node==null || !node.isEnd()){ break; } if(node.isEnd()){ sb.append("***"); i=j+1; continue; } j++; } if(i>=j){ sb.append(text.charAt(i)); i++; }else{ i=j; } } return sb.toString(); } ``` 此函数会逐一扫描给定字符串里的每一项成分,并依据预先建立好的规则决定保留原样还是替换成指定符号序列(这里选用的是三个星号)。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值