樹結構—Trie樹

 頗有段時間沒寫此係列了,今天咱們來講Trie樹,Trie樹的名字有不少,好比字典樹,前綴樹等等。node

一:概念this

     下面咱們有and,as,at,cn,com這些關鍵詞,那麼如何構建trie樹呢?spa

從上面的圖中,咱們或多或少的能夠發現一些好玩的特性。code

      第一:根節點不包含字符,除根節點外的每個子節點都包含一個字符。orm

      第二:從根節點到某一節點,路徑上通過的字符鏈接起來,就是該節點對應的字符串。內存

      第三:每一個單詞的公共前綴做爲一個字符節點保存。字符串

 

二:使用範圍get

     既然學Trie樹,咱們確定要知道這玩意是用來幹嗎的。hash

     第一:詞頻統計。it

            可能有人要說了,詞頻統計簡單啊,一個hash或者一個堆就能夠打完收工,但問題來了,若是內存有限呢?還能這麼

             玩嗎?因此這裏咱們就能夠用trie樹來壓縮下空間,由於公共前綴都是用一個節點保存的。

     第二: 前綴匹配

            就拿上面的圖來講吧,若是我想獲取全部以"a"開頭的字符串,從圖中能夠很明顯的看到是:and,as,at,若是不用trie樹,

            你該怎麼作呢?很顯然樸素的作法時間複雜度爲O(N2) ,那麼用Trie樹就不同了,它能夠作到h,h爲你檢索單詞的長度,

            能夠說這是秒殺的效果。

舉個例子:現有一個編號爲1的字符串」and「,咱們要插入到trie樹中,採用動態規劃的思想,將編號」1「計入到每一個途徑的節點中,

              那麼之後咱們要找」a「,」an「,」and"爲前綴的字符串的編號將會垂手可得。

三:實際操做

     到如今爲止,我想你們已經對trie樹有了大概的掌握,下面咱們看看如何來實現。

複製代碼

 package Algorithm;

public class Trie {
	private int SIZE=26;
	private TrieNode root;//字典樹的根

	Trie(){//初始化字典樹 
		root=new TrieNode();
	}

	private class TrieNode{//字典樹節點
		private int num;//有多少單詞經過這個節點,即節點字符出現的次數
		private TrieNode[]  son;//全部的兒子節點
		private boolean isEnd;//是否是最後一個節點
		private char val;//節點的值

		TrieNode(){
			num=1;
			son=new TrieNode[SIZE];
			isEnd=false;
		}
	}

	//創建字典樹
	public void insert(String str){//在字典樹中插入一個單詞
		if(str==null||str.length()==0){
			return;
		}
		TrieNode node=root;
		char[]letters=str.toCharArray();
		for(int i=0,len=str.length();i<len;i++){
			int pos=letters[i]-'a';
			if(node.son[pos]==null){
				node.son[pos]=new TrieNode();
				node.son[pos].val=letters[i];
			}else{
				node.son[pos].num++;
			}
			node=node.son[pos];
		}
		node.isEnd=true;
	}

	//計算單詞前綴的數量
	public int countPrefix(String prefix){
		if(prefix==null||prefix.length()==0){
			return-1;
		}
		TrieNode node=root;
		char[]letters=prefix.toCharArray();
		for(int i=0,len=prefix.length();i<len;i++){
			int pos=letters[i]-'a';
			if(node.son[pos]==null){
				return 0;
			} 
			else{
				node=node.son[pos];
			}
		}
		return node.num;
	}

	//在字典樹中查找一個徹底匹配的單詞.
	public boolean has(String str){
		if(str==null||str.length()==0){
			return false;
		}
		TrieNode node=root;
		char[]letters=str.toCharArray();
		for(int i=0,len=str.length();i<len;i++){
			int pos=letters[i]-'a';
			if(node.son[pos]!=null){
				node=node.son[pos];
			}else{
				return false;
			}
		}
		return node.isEnd;
	}

	//前序遍歷字典樹.
	public void preTraverse(TrieNode node){
		if(node!=null){
			System.out.print(node.val+"-");
			for(TrieNode child:node.son){
				preTraverse(child);
			}
		}
	}

	public TrieNode getRoot(){
		return this.root;
	}

	public static void main(String[]args){
		Trie tree=new Trie();
		String[]strs={"banana","band","bee","absolute","acm",};
		String[]prefix={"ba","b","band","abc",};
		for(String str:strs){
			tree.insert(str);
		}
		System.out.println(tree.has("abc"));
		tree.preTraverse(tree.getRoot());
		System.out.println();
		//tree.printAllWords();
		for(String pre:prefix){
			int num=tree.countPrefix(pre);
			System.out.println(pre+""+num);
		}
	}
}

複製代碼

相關文章
相關標籤/搜索