數據結構大都離不開數組和鏈表。他們是計算機中最基本的數據機構,基本全部的數據機構均可以有這兩種數據機構來實現。java
而鏈表是一種特殊的樹,樹更是一種特殊的圖。node
極客時間 數學專欄的做者的一段話,一直以爲很受用:算法
其實計算機到了最後仍是搞數學,咱們要作的就是如何將問題應用到數學在到編程上去。編程
數學思想到編程的實現大都分爲三步走數組
1.2.1 什麼是字典樹?數據結構
字典樹也能夠叫作前綴樹,其實就是將不少單詞組成的一種數據機構。一般都是樹形結構的全部叫作字典樹。ui
以下圖所示:this
跟節點一般都是空,不一樣的單詞組成一條條的通路,造成了一個樹狀結構。編碼
字典樹有兩種實現方式鏈表和數組。spa
由於字典樹的二維關係是很是稀疏很是動態的,因此採用鏈表來實現字典樹。
具體的代碼註釋以下:
static class TreeNode{
/** * 節點的數據void */
private char data;
/** * 子節點 */
private Map<Character,TreeNode> sons = null;
/** * 節點的解釋 */
private String explanation = null;
/** * 節點的前綴字符串 */
private String prefix = null;
public TreeNode(char data, String explanation, String prefix) {
this.data = data;
this.sons = new HashMap<>(16);
this.explanation = explanation;
this.prefix = prefix;
}
}
複製代碼
1.2.2 字典樹的操做
字典樹有兩種
由於字典樹的二維關係是很是稀疏很是動態的,
字典樹的操做有兩個
構建字典樹(Dynamic)
public static void buildPrefixTree(String word){
if(StringUtils.isEmpty(word)) {
return;
}
TreeNode findNode = headNode;
String prefix = "";
String explanation = null;
for(int i=0;i<word.length();i++){
char c = word.charAt(i);
Map<Character, TreeNode> sons = findNode.sons;
if(sons.containsKey(c)){
findNode = sons.get(c);
}else{
if(i == word.length()-1){
explanation = prefix + c;
}
TreeNode sonNode = new TreeNode(c,explanation,prefix);
sons.put(c,sonNode);
findNode = sonNode;
}
prefix += c;
}
}
複製代碼
查詢字典
/** * 在PrefixTree中查找 單詞 * @param word * @return */
public static TreeNode findWrod(String word){
if(StringUtils.isEmpty(word)) {
return null;
}
TreeNode findNode = headNode;
for(int i=0;i<word.length();i++){
char c = word.charAt(i);
Map<Character, TreeNode> sons = findNode.sons;
if( sons.size()!=0 && sons.containsKey(c)){
findNode = sons.get(c);
}else{
return null;
}
}
if(StringUtils.isEmpty(findNode.explanation)){
return null;
}
return findNode;
}
複製代碼
遍歷字典樹中的全部單詞
/** * 使用棧便利全部的單詞 */
public static void dfsByStack(){
Stack<TreeNode> stack = new Stack<>();
stack.push(headNode);
while(stack.size()>0){
TreeNode node = stack.pop();
if(!StringUtils.isEmpty(node.explanation)){
System.out.println(node.explanation);
}
Map<Character, TreeNode> sons = node.sons;
sons.forEach((sonKey,sonValue)->{
stack.push(sonValue);
});
}
}
複製代碼
字典樹的這三種操做其實均可以用遞歸來實現,可是最後一種的效率是明顯優於遞歸的,由於減小了大量的中間變量的建立,利用了棧模擬了遞歸調用。