在上一篇博客里简单的说了一下标准trie树的建立,本来说要做一个小型词典来用试试,结果这段时间有事就一直耽误到现在,今天抽了一点时间看看,首先我想到的是在我们输入某些单词的前面几个字母的时候下面的提示,那是trie树的模糊查找,便想了想去实现这个功能。
要想实现模糊查询,首先一点是得找到前缀所在的节点,例如我想查找以ac开头的单词,那么在建立了trie树之后就得在trie树中首先找到ab所在的节点,然后在考虑里面的是。这一步其实好实现,就跟插入单词基本相似一个个的匹配就完了。找到前缀所在的节点之后就得考虑在这个节点之内怎么找到我们想要的单词,基本的思路是,判断该节点处的单词标记是否是true如果是就表示这个单词应该匹配出来,那么问题来了,我直到它是要匹配出来的可我要怎么把它实现出来?还有匹配到了之后我还不能结束还要一直匹配下去,又应该怎么搞?
对于第一个问题,很容易想到用一个变量先逐个保存起来,匹配成功之后在将它保存到一个数组中去,而这个数组就专门用来保存所有匹配到的单词。
至于第二个问题,我想了较长一段时间,因为老是匹配的不对,尤其是前一个单词是后一个单词的一个前缀的时候,例如匹配到abc之后还要匹配abcd,abc匹配之后保存单词的数组就要向前推进前面保存的数据就会丢失,当时我想的是数组的下一个值的初始值就上一个单词,后来一想实在是太蠢了,如果还要匹配abdf不是GG了?正在愣住之际忽然想起迭代,哎呀,终于找到症结了,我把单词前缀作为一个变量传进去,再迭代赋值不就OK?
好了,有了解决方案就开始写了(很多程序员一开始都有这个毛病,觉得听懂了,想明白了,好简单,不去动手写,结果真到写的时候才发现什么都不会),经过一番折腾相对完善的代码如下
//模糊搜索单词
public String [] getwordsBypre(String wordPre){
String[] result=null;
wordPre=wordPre.trim().toLowerCase();
char []letters=wordPre.trim().toCharArray();
TrieNode node=root;
for(int i=0;i<letters.length;i++){
int pos=letters[i]-'a';
if(node.sons[pos]==null){
break;
}else{
node=node.sons[pos];
}
}
if(node.isEnd){//本身是一个单词也要匹配到
words[wordsNum++]="";//words是一个全局变量,在构造函数中初始化全部赋值为""
}
for(TrieNode child:node.sons){
getAllNext("",child);
}
result=new String[wordsNum];
for(int i=0;i<wordsNum;i++){
result[i]=wordPre+words[i];
}
return result;
}
//获得一个节点下的所有的单词
private void getAllNext(String pre,TrieNode node){
if(wordsNum>=10){//这里我是根据实际情况做了一个限制不要模糊匹配那么多,10个够了
return ;
}
if(node!=null){
pre+=node.value;//pre是单词前缀,在后面的迭代过程中随着节点的不断深入,pre也要保存前面节点的值
if(node.isEnd){
words[wordsNum]=pre+words[wordsNum];
wordsNum++;
}
for(TrieNode child:node.sons){
getAllNext(pre,child);//迭代
}
}
}
这里是直接写到trie树这个结构里面的方法,就是我写的那个标准的trie树(http://blog.csdn.net/my_sunshine_y/article/details/50497936)。测试类代码:
package TrieTree;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
public class test {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
InputStream iis=test.class.getClassLoader().getResourceAsStream("a.txt");
myTrie t=new myTrie();
InputStreamReader isr=new InputStreamReader(iis);
BufferedReader br=new BufferedReader(isr);
String str ="";
while((str = br.readLine())!=null&&!str.trim().equals("")){
String word=str.trim();
System.out.println(word);
t.insertWord(word);
}
System.out.println(t.findWord("abc"));
System.out.println();
String [] re=t.getwordsBypre("ai");
for(String s:re){
System.out.println(s);
}
}
}
其中a.txt在我工程目录下,这里通过类加载器来读取。