数据结构——字典树Trie(介绍、Java实现)
文章目录
- 字典树Trie
- 介绍
- Java实现
字典树Trie
介绍
字典树是一种专门用于处理字符串的高效数据结构,也称为前缀树或单词查找树。
定义:
字典树是一种树形数据结构,用于存储字符串集合,具有以下特点:
- 根节点不包含字符,每个子节点代表一个字符
- 从根节点到某一节点的路径上经过的字符连接起来,构成对应的字符串
- 每个节点的所有子节点代表的字符都不相同
核心特性:
- 前缀共享:具有相同前缀的字符串共享路径
- 快速检索:查找时间复杂度与字符串长度相关,与数据量无关
- 前缀匹配:天然支持前缀搜索
Java实现
我们了解完字典树数据结构,尝试手搓一个简化版的字典树加强理解,在这个开源项目中实现。
GitCode - 全球开发者的开源社区,开源代码托管平台
- 节点TrieNode
public class TrieNode {private TrieNode[] children; // 子节点数组,一共26个private boolean isWord; // 是否结尾即是否是单词结尾public TrieNode(){children = new TrieNode[26];isWord = false;}public boolean containKey(char c){return children[c - 'a'] != null;}public void putChar(char c){children[c - 'a'] = new TrieNode();}public TrieNode getChild(char c){if (children[c - 'a'] == null) return null;return children[c - 'a'];}public void setIsWord(boolean isWord){this.isWord = isWord;}public boolean isWordOrNot(){return isWord;}
}
- 字典树Trie
public class Trie {private TrieNode root;/*** 构造函数,初始化Trie树* 创建一个空的根节点*/public Trie() {root = new TrieNode();}/*** 插入单词到Trie树中* @param word 要插入的单词*/public void insert(String word) {if(word == null || word.length() == 0) return;TrieNode node = root;// 遍历单词字母for(int i = 0; i < word.length(); i++) {char c = word.charAt(i);if (!node.containKey(c)){node.putChar(c);}node = node.getChild(c);}node.setIsWord(true); // 设置为单词结尾}/*** 在Trie树中搜索指定单词* @param word 要搜索的单词* @return 如果单词存在返回true,否则返回false*/public boolean searchWord(String word) {if(word == null || word.length() == 0) return false;TrieNode node = searchPrefix(word);return node != null && node.isWordOrNot();}/*** 检查Trie树中是否存在指定前缀* @param prefix 要检查的前缀* @return 如果前缀存在返回true,否则返回false*/public boolean startsWith(String prefix) {if(prefix == null || prefix.length() == 0) return false;return searchPrefix(prefix) != null;}/*** 查找前缀对应的节点* @param prefix 要查找的前缀* @return 如果前缀存在,返回前缀最后一个字符对应的节点;否则返回null*/private TrieNode searchPrefix(String prefix) {TrieNode node = root;for (int i = 0; i < prefix.length(); i++) {char c = prefix.charAt(i);if (!node.containKey(c)){return null;}node = node.getChild(c);}return node;}/*** 搜索所有以指定前缀开头的单词* @param prefix 搜索的前缀* @return 所有匹配的单词列表*/public List<String> searchWordsWithPrefix(String prefix){if(prefix == null || prefix.length() == 0) return new ArrayList<>();List<String> result = new ArrayList<>();TrieNode node = searchPrefix(prefix);if(node != null){collectWordsStartWithPrefix(node, result, new StringBuilder(prefix));}return result;}/*** 递归收集以指定节点开始的所有单词* @param node 当前节点* @param result 结果列表,用于存储找到的单词* @param strbuilder 当前构建的字符串*/private void collectWordsStartWithPrefix(TrieNode node, List<String> result, StringBuilder strbuilder) {if(node.isWordOrNot()){result.add(strbuilder.toString());}for(int i = 0;i < 26;i ++){char c = (char)('a' + i);if(node.containKey(c)){strbuilder.append(c);collectWordsStartWithPrefix(node.getChild(c), result, strbuilder);strbuilder.deleteCharAt(strbuilder.length() - 1); // 回溯}}}public static void main(String[] args) {Trie trie = new Trie();trie.insert("apple");trie.insert("application");trie.insert("blue");trie.insert("blueface");trie.insert("blwww");System.out.println(trie.searchWord("blue"));System.out.println(trie.searchWordsWithPrefix("app"));System.out.println(trie.searchWordsWithPrefix("bl"));}
}
- 测试结果:
true
[apple, application]
[blue, blueface, blwww]