前綴樹

前綴樹是什么

前綴樹是一種樹結(jié)構(gòu),其中的鍵通常是字符串。與二叉查找樹不同,鍵不是直接保存在節(jié)點(diǎn)中,而是由節(jié)點(diǎn)在樹中的位置決定。一個(gè)節(jié)點(diǎn)的所有子孫都有相同的前綴,也就是這個(gè)節(jié)點(diǎn)對(duì)應(yīng)的字符串,而根節(jié)點(diǎn)對(duì)應(yīng)空字符串。一般情況下,不是所有的節(jié)點(diǎn)都有對(duì)應(yīng)的值,只有葉子節(jié)點(diǎn)和部分內(nèi)部節(jié)點(diǎn)所對(duì)應(yīng)的鍵才有相關(guān)的值。

前綴樹基本性質(zhì)

1,根節(jié)點(diǎn)不包含字符,除根節(jié)點(diǎn)意外每個(gè)節(jié)點(diǎn)只包含一個(gè)字符。
2,從根節(jié)點(diǎn)到某一個(gè)節(jié)點(diǎn),路徑上經(jīng)過的字符連接起來,為該節(jié)點(diǎn)對(duì)應(yīng)的字符串。
3,每個(gè)節(jié)點(diǎn)的所有子節(jié)點(diǎn)包含的字符串不相同。
優(yōu)點(diǎn):
可以最大限度地減少無謂的字符串比較,故可以用于詞頻統(tǒng)計(jì)和大量字符串
排序。
跟哈希表比較:
1,最壞情況時(shí)間復(fù)雜度比hash表好
2,沒有沖突,除非一個(gè)key對(duì)應(yīng)多個(gè)值(除key外的其他信息)
3,自帶排序功能(類似Radix Sort),中序遍歷trie可以得到排序。

缺點(diǎn):
1,雖然不同單詞共享前綴,但其實(shí)trie是一個(gè)以空間換時(shí)間的算法。其每一個(gè)字符都可能包含至多字符集大小數(shù)目的指針(不包含衛(wèi)星數(shù)據(jù))。
每個(gè)結(jié)點(diǎn)的子樹的根節(jié)點(diǎn)的組織方式有幾種。1>如果默認(rèn)包含所有字符集,則查找速度快但浪費(fèi)空間(特別是靠近樹底部葉子)。2>如果用鏈接法(如左兒子右兄弟),則節(jié)省空間但查找需順序(部分)遍歷鏈表。3>alphabet reduction: 減少字符寬度以減少字母集個(gè)數(shù)。,4>對(duì)字符集使用bitmap,再配合鏈接法。
2,如果數(shù)據(jù)存儲(chǔ)在外部存儲(chǔ)器等較慢位置,Trie會(huì)較hash速度慢(hash訪問O(1)次外存,Trie訪問O(樹高))。

如何生成前綴樹

結(jié)點(diǎn)的值由結(jié)點(diǎn)的位置決定,比如該樹是一個(gè)字符串樹.
我們可以定義結(jié)點(diǎn)有一個(gè)長(zhǎng)度為26的結(jié)點(diǎn)數(shù)組,利用字符和'a'的差值
確定字符要存的位置,比如a-'a'=0,則a字符存到root[0]位置,c-'a'=2,那么c存到root[2]位置

前綴樹代碼實(shí)現(xiàn)和測(cè)試:

package com.algorithm.practice.tree;

import org.omg.PortableInterceptor.INACTIVE;

public class CreatTrieTree {
    public static class TrieTree {
        int path;//略過的次數(shù)---有多少字符串包含此結(jié)點(diǎn)到根結(jié)點(diǎn)的所有字符
        int end;//以該結(jié)點(diǎn)為最后一個(gè)字符的字符串
        TrieTree[] nodes;

        public TrieTree() {
            path = 0;
            end = 0;
            nodes = new TrieTree[26];
        }
    }

    public static class Trie {
        private TrieTree root;

        public Trie() {
            root = new TrieTree();
        }

        public void insert(String word) {
            if (word == null || "".equals(word)) {
                return;
            }
            TrieTree node = root;
            int index;
            for (char c : word.toCharArray()//遍歷字符串中的每一個(gè)字符
            ) {
                index = c - 'a';
                if (node.nodes[index] == null) {
                    node.nodes[index] = new TrieTree();
                }
                node = node.nodes[index];
                node.path++;
            }
            node.end++;
        }


public  int search(String str) {
            if (str == null || "".equals(str)) {
                return 0;
            }
            char[] chars = str.toCharArray();
            TrieTree node = root;
            int index;
            for (int i = 0; i < chars.length; i++) {
                index = chars[i] - 'a';
                if (node.nodes[index] == null) {
                    return 0;
                }
                node = node.nodes[index];
            }
            return node.end;
        }

        public void delete(String str) {
            if (search(str)!=0){ //前綴樹中有才進(jìn)行刪除
             char[]chars=str.toCharArray();
             int index;
             TrieTree node=root;
             for(int i=0;i<chars.length;i++){
                 index=chars[i]-'a';
                 if (--node.nodes[index].path==0){
                     node.nodes[index]=null;
                     return;
                 }
                 node=node.nodes[index];
             }
             node.end--;
            }
        }

        public int preFixNumber(String str){
            if (str==null||"".equals(str)){
                return 0;
            }
            char[] chars=str.toCharArray();
            TrieTree node=root;
            int index;
            for(int i=0;i<chars.length;i++){
                index=chars[i]-'a';
                if (node.nodes[index]==null){
                    return 0;
                }
                node=node.nodes[index];
            }
            return node.path;
        }
    }
    public static void main(String[] args) {
        Trie trie = new Trie();
        System.out.println(trie.search("zuo"));
        trie.insert("zuo");
        System.out.println(trie.search("zuo"));
        trie.delete("zuo");
        System.out.println(trie.search("zuo"));
        trie.insert("zuo");
        trie.insert("zuo");
        trie.delete("zuo");
        System.out.println(trie.search("zuo"));
        trie.delete("zuo");
        System.out.println(trie.search("zuo"));
        trie.insert("zuoa");
        trie.insert("zuoac");
        trie.insert("zuoab");
        trie.insert("zuoad");
        trie.delete("zuoa");
        System.out.println(trie.search("zuoa"));
        System.out.println(trie.preFixNumber("zuo"));

    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 叫前綴樹更容易理解字典樹的樣子 Trie又被稱為前綴樹、字典樹,所以當(dāng)然是一棵樹。上面這棵Trie樹包含的字符串集...
    Drama_Du閱讀 490評(píng)論 0 0
  • 1. 前綴樹的應(yīng)用 自動(dòng)補(bǔ)全、拼寫檢查、最長(zhǎng)前綴匹配、單詞游戲 2. 字典樹的結(jié)構(gòu) Trie樹是一個(gè)有根的樹,其結(jié)...
    myFamily329閱讀 2,459評(píng)論 0 2
  • 聲明:摘自github:https://github.com/ZtesoftCS/go-ethereum-code...
    藍(lán)Renly閱讀 851評(píng)論 0 0
  • 字典樹介紹 又稱單詞查找樹,Trie樹,是一種樹形結(jié)構(gòu),是一種哈希樹的變種。典型應(yīng)用是用于統(tǒng)計(jì),排序和保存大量的字...
    遠(yuǎn)o_O閱讀 5,977評(píng)論 1 5
  • 在我的印象里,媽媽的愛像春雨,潤(rùn)物細(xì)無聲,爸爸的愛,像一座大山,雖然不言不語(yǔ),卻勝過千言無語(yǔ)。他們都是天下最好的爸...
    小考拉俱樂部閱讀 361評(píng)論 0 0

友情鏈接更多精彩內(nèi)容