前缀树

基础知识

Trie树。又称之为单词查找树或者键树,是一种树形结构。应用于统计和排序大量的字符串。常被搜索引擎系统用于文本词频统计。它的优点:能够最大限度的减少无谓的字符串比较,查询效率比哈希表高。

核心思想是以空间换时间。利用记录字符串公共前缀来降低查询时间的开销。

3个基本性质

  1. 根节点不包含字符,除根节点外每一个节点都只包含一个字符
  2. 从根节点到某一节点,路径上经过的字符连接起来,为该节点所对应的字符串
  3. 每个节点的所有子节点所包含的字符都不同。
  4. 每个节点对应一个前缀,叶节点对应最长前缀,即单词本身。

功能

应该实现查询,插入,前缀查询的功能。

数据结构组成

Trie,又称前缀树或字典树,是一棵有根树,其每个节点包含以下字段:

指向子节点的指针数组children。对于本题而言,数组长度为26,即小写英文字母的数量。此时children[0]对应小写字母 a。

布尔字段isEnd,表示该节点是否为字符串的结尾。

实现

插入

我们从字典树的根开始,插入字符串。对于当前字符对应的子节点,有两种情况:

  • 子节点存在。沿着指针移动到子节点,继续处理下一个字符。
  • 子节点不存在。创建一个新的子节点,记录在children数组的对应位置上,然后沿着指针移动到子节点,继续搜索下一个字符。

重复以上步骤,直到处理字符串的最后一个字符,然后将当前节点标记为字符串的结尾。

查找前缀

我们从字典树的根开始,查找前缀。对于当前字符对应的子节点,有两种情况:

子节点存在。沿着指针移动到子节点,继续搜索下一个字符。

子节点不存在。说明字典树中不包含该前缀,返回空指针。

重复以上步骤,直到返回空指针或搜索完前缀的最后一个字符。

若搜索到了前缀的末尾,就说明字典树中存在该前缀。此外,若前缀末尾对应节点的isEnd为真,则说明字典树中存在该字符串。

查找

实现了查找前缀的函数,就可以直接调用这个函数,检查返回的node是否不为空且是叶子节点。若是则说明此时的字符串存在,不然就不存在。

package JavaCode.leetcode.DataStructure.Tree;

 class Trie {
//Trie的两个属性,指向子节点的指针数组和表示该节点是否为结尾的布尔值
private Trie[] children;
private boolean isEnd; //构造
public Trie() {
children = new Trie[26];
isEnd = false;
} //插入节点。
public void insert(String word) {
Trie node = this;//指针指向当前的根
for (int i = 0; i < word.length(); i++) {
char ch = word.charAt(i);//待插入的字符
int index = ch - 'a';//参数
//当前的节点为null,就新建一个节点
if (node.children[index] == null) {
node.children[index] = new Trie();
}
//当前节点不为null,就将node沿指针移动到子节点
node = node.children[index];
}
//完成插入后,就将此时node所指向的节点isEnd置为true
node.isEnd = true;
}
//查询前缀树中是否含有本字符串,使用查询前缀和的函数得到节点node,
//若返回的node不为null,则说明找到了word的前缀,且如果此时isEnd为true,说明node是叶子
//则说明此时的word存在于前缀树中。
public boolean search(String word) {
Trie node = searchPrefix(word);
return node != null && node.isEnd;
} //查询前缀
public boolean startsWith(String prefix) {
//只要返回值不为null,说明搜索到了前缀的末尾就为true,否则为false
return searchPrefix(prefix) != null;
} private Trie searchPrefix(String prefix) {
Trie node = this;//指针指向当前的根
for (int i = 0; i < prefix.length(); i++) {
//当前访问的字符及其参数
char ch = prefix.charAt(i);
int index = ch - 'a';
//访问的节点不存在,就返回一个null
if (node.children[index] == null) {
return null;
}
//访问的节点存在,就沿着指针指向的节点移动
node = node.children[index];
}
return node;//最后搜索到了末尾就返回这个末尾的节点,说明存在这个前缀
}
}

最新文章

  1. ZeroMQ:云时代极速消息通信库
  2. 20145220&amp;20145209&amp;20145309信息安全系统设计基础实验报告(3)
  3. iOS关于启动页自定义特殊处理
  4. Retro 2013
  5. Unity3D SceneView Camera
  6. 关于c3p0配置详细说明
  7. QT开发pjsip的VOIP,A8平台运行
  8. RESTEasy + JBOSS 7 Hello world application---reference
  9. 【IOS学习基础】内存管理
  10. 2、MyEclipse和Eclipse调优,MyEclipse配置(tomcat和jdk的内存设置),jar引入相关知识点,将Java项目编程web项目的办法
  11. redis基本类型以及优点特性
  12. Array.find()和Array.findIndex()
  13. org.apache.maven.archiver.mavenarchiver.getmanifest怎么解决
  14. 深度优先搜索(DFS)和广度优先搜索(BFS)
  15. nginx 、springMvc(非分布式)相应的限流、消峰
  16. Lua C API 遍历 table
  17. Java Date 日期 时间 相关方法
  18. 訪问站点时仅仅是显示主页(index.jsp),没有请求连接数据库读取数据。
  19. java—数据存储过程 (54)
  20. 整合quickx到普通cocos2dx

热门文章

  1. SQL语句(四)联表查询
  2. 自学vue第二天,从入门到放弃(生命周期的理解)
  3. wps查找替换使用通配符一个实例
  4. 【Unity3D】Android App Bundle(aab)打包上架Google Play介绍
  5. Install Redmine on Virtual Machine with Vagrant
  6. 在Django中使用Channels功能
  7. mybaits进阶01
  8. 题解 Connect
  9. spring cloud 的hystrix 熔断器 和feign 调用的使用
  10. 在npm Vue单页面的环境下,兄弟组件之间通信Bus