1. 程式人生 > >trie樹實現模糊查詢

trie樹實現模糊查詢

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