前綴樹及其Java實現


前綴樹

基礎知識

Trie樹。又稱之為單詞查找樹或者鍵樹,是一種樹形結構。應用於統計和排序大量的字符串。常被搜索引擎系統用於文本詞頻統計。它的優點:能夠最大限度的減少無謂的字符串比較,查詢效率比哈希表高。

核心思想是以空間換時間。利用記錄字符串公共前綴來降低查詢時間的開銷。

3個基本性質

  1. 根節點不包含字符,除根節點外每一個節點都只包含一個字符
  2. 從根節點到某一節點,路徑上經過的字符連接起來,為該節點所對應的字符串
  3. 每個節點的所有子節點所包含的字符都不同。
  4. 每個節點對應一個前綴,葉節點對應最長前綴,即單詞本身。

功能

應該實現查詢,插入,前綴查詢的功能。

數據結構組成

Trie,又稱前綴樹或字典樹,是一棵有根樹,其每個節點包含以下字段:

指向子節點的指針數組children。對於本題而言,數組長度為26,即小寫英文字母的數量。此時children[0]對應小寫字母 a。
布爾字段isEnd,表示該節點是否為字符串的結尾。

實現

插入

我們從字典樹的根開始,插入字符串。對於當前字符對應的子節點,有兩種情況:

  • 子節點存在。沿着指針移動到子節點,繼續處理下一個字符。
  • 子節點不存在。創建一個新的子節點,記錄在children數組的對應位置上,然后沿着指針移動到子節點,繼續搜索下一個字符。

重復以上步驟,直到處理字符串的最后一個字符,然后將當前節點標記為字符串的結尾。

查找前綴

我們從字典樹的根開始,查找前綴。對於當前字符對應的子節點,有兩種情況:

子節點存在。沿着指針移動到子節點,繼續搜索下一個字符。
子節點不存在。說明字典樹中不包含該前綴,返回空指針。
重復以上步驟,直到返回空指針或搜索完前綴的最后一個字符。

若搜索到了前綴的末尾,就說明字典樹中存在該前綴。此外,若前綴末尾對應節點的isEnd為真,則說明字典樹中存在該字符串。

查找

實現了查找前綴的函數,就可以直接調用這個函數,檢查返回的node是否不為空且是葉子節點。若是則說明此時的字符串存在,不然就不存在。

package JavaCode.leetcode.DataStructure.Tree;

 class Trie {
     //Trie的兩個屬性,指向子節點的指針數組和表示該節點是否為結尾的布爾值
     private Trie[] children;
     private boolean isEnd;
    
     //構造
     public Trie() {
         children = new Trie[26];
         isEnd = false;
     }
    
     //插入節點。
     public void insert(String word) {
         Trie node = this;//指針指向當前的根
         for (int i = 0; i < word.length(); i++) {
             char ch = word.charAt(i);//待插入的字符
             int index = ch - 'a';//參數
             //當前的節點為null,就新建一個節點
             if (node.children[index] == null) {
                 node.children[index] = new Trie();
             }
             //當前節點不為null,就將node沿指針移動到子節點
             node = node.children[index];
         }
         //完成插入后,就將此時node所指向的節點isEnd置為true
         node.isEnd = true;
     }
     //查詢前綴樹中是否含有本字符串,使用查詢前綴和的函數得到節點node,
     //若返回的node不為null,則說明找到了word的前綴,且如果此時isEnd為true,說明node是葉子
     //則說明此時的word存在於前綴樹中。
     public boolean search(String word) {
         Trie node = searchPrefix(word);
         return node != null && node.isEnd;
     }

     //查詢前綴
     public boolean startsWith(String prefix) {
         //只要返回值不為null,說明搜索到了前綴的末尾就為true,否則為false
         return searchPrefix(prefix) != null;
     }

     private Trie searchPrefix(String prefix) {
         Trie node = this;//指針指向當前的根
         for (int i = 0; i < prefix.length(); i++) {
             //當前訪問的字符及其參數
             char ch = prefix.charAt(i);
             int index = ch - 'a';
             //訪問的節點不存在,就返回一個null
             if (node.children[index] == null) {
                 return null;
             }
             //訪問的節點存在,就沿着指針指向的節點移動
             node = node.children[index];
         }
         return node;//最后搜索到了末尾就返回這個末尾的節點,說明存在這個前綴
     }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM