在上一篇博客裏簡單的說了一下標準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在我工程目錄下,這裏通過類加載器來讀取。