当前位置: 首页 > 科技观察

数据结构:字典树Trie——键入一个词关联一串词

时间:2023-03-16 22:08:24 科技观察

1.前言Trie历史字典树Trie这个词来自检索。1912年,AxelThue首先抽象描述了一组字符串数据结构的存储方式,就是Trie的思想。EdwardFredkin在1960年独立描述了这个想法,创造了术语Trie。看,有多少程序员想为一个词、一个方法名、一个属性名砸破脑袋!二、字典树数据结构在计算机科学中,字典树(Trie)也被称为“单词查找树”或“数字树”,有时也被称为基数树或前缀树(因为它可以通过前缀的方式来完成)指数)。-它是一棵搜索树,一种排序的数据结构,通常用于存储动态集或键为字符串的关联数组。与二叉搜索树不同的是,键不直接存储在节点中,而是由节点在树中的位置决定。一个节点的所有后代都有相同的前缀,就是这个节点对应的字符串,根节点对应的是空字符串。一般来说,并不是所有的节点都有对应的值,只有叶子节点对应的键和一些内部节点有相关的值。这是一个将战斗词串按照字母拆分成字典树存储的图。键在节点中注释,值在节点下方注释。每个完整的英文单词对应一个特定的整数。即26个字母对应的ASCII转换值。3、词典树结构的实现词典树中存储了26个字母,也就是说在实现过程中,每个节点分支有26个槽位用于存储可能的字母组合。同理,如果是一棵数字树,就是10个数字的组合,每棵字典树上节点对应的分支有10个操作来存储可能的数字组合。接下来,我们将基于Java语言实现存储字典树和遍历索引的功能。源码地址:https://github.com/fuzhengwei/java-algorithms本章源码:https://github.com/fuzhengwei/java-algorithms/tree/main/data-structures/src/main/java/trie1.twigNodepublicclassTrieNode{/**形成一条链*/publicTrieNode[]slot=newTrieNode[26];/**字母*/publiccharc;/**单词:数字>0表示一个单词*/publicbooleanisWord;/**前缀*/publicint前缀;/**word:一个特定的单词字符串*/publicStringword;/**explanation:词的注释说明*/publicStringexplain;}字典树的节点需要包含嵌入该节点的关联节点,后面是该节点的字母,这个字母是否是一个词,单词的前缀、单词字符串和当前单词的可选注释。2.插入元素publicvoidinsert(Stringwords,Stringexplain){TrieNoderoot=wordsTree;char[]chars=words.toCharArray();for(charc:chars){intidx=c-'a';//-a从0开始,参考ASCII码表if(root.slot[idx]==null){root.slot[idx]=newTrieNode();}root=root.slot[idx];根.c=c;根前缀++;}root.explain=解释;//单词的注释解释信息root.isWord=true;//markafterloopdismandingword}insert方法接收word和comment信息,根据char拆分出一个word,计算索引位置并存储。存储完成后,存储标记的词和词所附的注释信息。3.索引元素publicListsearchPrefix(Stringprefix){TrieNoderoot=wordsTree;char[]chars=prefix.toCharArray();StringBuilder缓存=newStringBuilder();//精确匹配:根据前缀查找for(charc:chars){intidx=c-'a';//匹配为空if(idx>root.slot.length||idx<0||root.slot[idx]==null){returnCollections.emptyList();}cache.append(c);root=root.slot[idx];}//模糊匹配:根据前缀的最后一个词,递归遍历所有词ArrayListlist=newArrayList<>();if(root.prefix!=0){for(inti=0;i=15){返回列表;}}}}returnlist;}protectedvoidcollect(TrieNodetrieNode,Stringpre,Listqueue,intresultLimit){//查找单词if(trieNode.isWord){trieNode.word=pre;//将检索到的单词保存到队列queue.add(trieNode.word+"->"+trieNode.explain);如果(queue.size()>=resultLimit){返回;}}//递归调用,查找词for(inti=0;i=15是判断索引的最??大长度。如果超过这个数字,索引将停止。毕竟这是一种O(n)时间复杂度的Operation,如果加载几十万个单词进行匹配,执行速度还是比较耗时的。4.Trie函数测试@Testpublicvoidtest_trie(){Trietrie=newTrie();//存入trie.insert("bat","Dachang");trie.insert("批量","批量");trie.insert("婊子","表子");trie.insert("战斗","战斗");logger.info(trie.toString());//检索ListtrieNodes=trie.searchPrefix("ba");logger.info("Testresult:{}",JSON.toJSONString(trieNodes));}下面是一些字母相似的词和名词,用于测试。也可以尝试读取txt文件,检索存储几十万字,用于检索验证。测试结果06:21:38.226[main]INFOtrie.__test__.TrieTest-测试结果:["bat->Dachang","batch->batch","battle->battle"]Processfinishedwithexitcodepassedthetest结果可以看出,所有ba开头的词都被检索出来了。这也是字典树核心功能的体现。在学习过程中,读者可以尝试在搜索方法体中打一些断点,看看具体的执行过程,以方便学习整个执行步骤。五。常见的面试题简单描述一下字典树的数据结构。描述如何实现字典树。字典树实际业务场景示例【排序、全文搜索、网络搜索引擎、生物信息】字典树的存储和检索时间复杂字典树还有哪些实现【后缀树、哈希树、帽子树]

猜你喜欢