1. 程式人生 > >Java實現單詞樹(trie)

Java實現單詞樹(trie)

package com.shundong.utils;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/** 
 * 一個只能處理26個字母的單詞樹(trie)
 * 空間換時間 T(n) = O(n) 
 * ps:如果缺陷 歡迎留言
 * @author shundong
 * @data 2018-10-13
 */

public class FindWordsTrie{
	//一個Trie樹有一個根節點
	private Vertex root;

	//內部類or節點類
	protected class Vertex{
		protected int words;
		protected int prefixes;
		//每個節點包含26個子節點(型別為自身)
		protected Vertex[] edges;
		Vertex() {
			words = 0;
			prefixes = 0;
			edges = new Vertex[26];
			for (int i = 0; i < edges.length; i++) {
				edges[i] = null;
			}
		}
	}

	public FindWordsTrie () {
		root = new Vertex();
	}

	/** 
	 * 列出List所有單詞
	 * @return
	 */
	public List< String> listAllWords() {

		List< String> words = new ArrayList< String>();
		Vertex[] edges = root.edges;

		for (int i = 0; i < edges.length; i++) {
			if (edges[i] != null) {
				String word = "" + (char)('a' + i);
				depthFirstSearchWords(words, edges[i], word);
			}
		}        
		return words;
	}

	/** 
	 * Depth First在Trie中搜索單詞並將它們新增到List中。
	 * @param words
	 * @param vertex
	 * @param wordSegment
	 */
	private void depthFirstSearchWords(List words, Vertex vertex, String wordSegment) {
		Vertex[] edges = vertex.edges;
		boolean hasChildren = false;
		for (int i = 0; i < edges.length; i++) {
			if (edges[i] != null) {
				hasChildren = true;
				String newWord = wordSegment + (char)('a' + i);                
				depthFirstSearchWords(words, edges[i], newWord);
			}            
		}
		if (!hasChildren) {
			words.add(wordSegment);
		}
	}

	public int countPrefixes(String prefix) {
		return countPrefixes(root, prefix);
	}

	private int countPrefixes(Vertex vertex, String prefixSegment) {
		if (prefixSegment.length() == 0) { //到達單詞的最後一個字元
			return vertex.prefixes;
		}
		char c = prefixSegment.charAt(0);
		int index = c - 'a';
		if (vertex.edges[index] == null) { // 這個詞不存在
			return 0;
		} else {
			return countPrefixes(vertex.edges[index], prefixSegment.substring(1));
		}        
	}

	public int countWords(String word) {
		return countWords(root, word);
	}    

	private int countWords(Vertex vertex, String wordSegment) {
		if (wordSegment.length() == 0) { //到達單詞的最後一個字元
			return vertex.words;
		}
		char c = wordSegment.charAt(0);
		int index = c - 'a';
		if (vertex.edges[index] == null) { // 這個詞不存在
			return 0;
		} else {
			return countWords(vertex.edges[index], wordSegment.substring(1));
		}        

	}
	/** 
	 * 在Trie上新增一個單詞
	 * @param word 要新增的詞
	 */
	public void addWord(String word) {
		addWord(root, word);
	}
	/** 
	 * 新增指定頂點的單詞
	 * @param vertex 指定的頂點
	 * @param word 要新增的詞
	 */
	private void addWord(Vertex vertex, String word) {
		if (word.length() == 0) { //如果已新增該單詞的所有字元
			vertex.words ++;
		} else {
			vertex.prefixes ++;
			char c = word.charAt(0);
			c = Character.toLowerCase(c);
			int index = c - 'a';
			if (vertex.edges[index] == null) { //如果邊緣不存在
				vertex.edges[index] = new Vertex();
			}
			addWord(vertex.edges[index], word.substring(1)); //去下一個
		}
	}
	//簡單的測試測試
	public static void main(String args[])  
	{
		FindWordsTrie trie = new FindWordsTrie();
		trie.addWord("cabbage");
		trie.addWord("cabbage");
		trie.addWord("cabbage");
		trie.addWord("cabbage");
		trie.addWord("cabin");
		trie.addWord("berte");
		trie.addWord("cabbage");
		trie.addWord("english");
		trie.addWord("establish");
		trie.addWord("good");

		//				System.out.println(trie.root.prefixes);
		//				System.out.println(trie.root.words);
		//				List< String> list = trie.listAllWords();
		//				Iterator listiterator = list.listIterator();
		//				//遍歷
		//				while(listiterator.hasNext())
		//				{
		//					String str = (String)listiterator.next();
		//					System.out.println(str);
		//				}
		int count = trie.countPrefixes("c");//此處傳參
		int count1=trie.countWords("cabbage");
		System.err.println("單詞c 字首個數為:"+count);
		System.err.println("cabbage 單詞的個數為:"+count1);
	}
}