Trie树

Trie树

Trie树,又叫单词查找树,前缀树。是一种非常高效的储存字符串的数据结构。它可以在 O ( n ) (n为查找字符串的长度) O(n)\text{(n为查找字符串的长度)} O(n)(n为查找字符串的长度)时间复杂度内进行增删改查,非常的快。即使字符串变多,它的效率也不会降低。

实现原理

顾名思义,Trie树就是一颗树,这颗树有多少个节点?如果你存的字符串里的字符包括ASCII码,那么每个节点就有128或者256个子节点,如果你查找的字符串都是由26个小写(或者大写)字母组成,那么每个节点就有26个子节点。

我们以26子节点的单词查找树为例,它的每一个树干就代表着一个字母,从左到右依次为a-z。当你插入一个单词例如aabbc,那么Trie树就会从根节点开始,开辟一条路径向下。比如a就会走第一条路,又是一个a再往下走第一条路,到了b就往下走第二条路,以此类推。你插入一个长度为5的单词后,Trie的树的高度就从1变成了6。然而,如果你再插入一个aac,你会发现高度还是6,唯一不同之处就是多了一条分支c

                                root
                              / | |... \
                            a
                          / | |... \ 
                         a
                       / | |... \
                         b c
                       / | |... \
                         b
                      / | |... \
                          c

需要注意的是,我们在插入一个单词后要在当前节点维护一个布尔值hasWord,如果为true就代表存在一个在当前位置结束的字符串。比如插入apple,我们查找app,这时你会发现确实存在这个节点,但很明显并没有插入这个单词,因为你查找的是某个已插入单词的前缀,当然除非你只要查找前缀。

代码模板

C++

class Trie {
private:
    Trie* nodes[26] = {nullptr};
    bool hasWord;
public:
    Trie() {
        hasWord = false;
    }

    void insert(string word) {
        Trie* cur = this;
        for (auto ch : word) {
            int nex = ch - 'a';
            if (!cur->nodes[nex]) cur->nodes[nex] = new Trie();
            cur = cur->nodes[nex];
        }
        cur->hasWord = true;
    }

    bool search(string word) {
        Trie* cur = this;
        for (auto ch : word) {
            cur = cur->nodes[ch - 'a'];
            if (!cur) return false;
        }
        return cur->hasWord;
    }

    bool startsWith(string prefix) {
        Trie* cur = this;
        for (auto ch : prefix) {
            cur = cur->nodes[ch - 'a'];
            if (!cur) return false;
        }
        return true;
    }
};

Java

class Trie {
    private Trie[] nodes;
    private boolean hasWord;
    public Trie() {
        nodes = new Trie[26];
        hasWord = false;
    }
    
    public void insert(String word) {
        Trie cur = this;
        for (char ch : word.toCharArray()) {
            int nex = ch - 'a';
            if (cur.nodes[nex] == null) cur.nodes[nex] = new Trie();
            cur = cur.nodes[nex];
        }
        cur.hasWord = true;
    }
    
    public boolean search(String word) {
        Trie cur = this;
        for (char ch : word.toCharArray()) {
            cur = cur.nodes[ch - 'a'];
            if (cur == null) return false;
        }
        return cur.hasWord;
    }
    
    public boolean startsWith(String prefix) {
        Trie cur = this;
        for (char ch : prefix.toCharArray()) {
            cur = cur.nodes[ch - 'a'];
            if (cur == null) return false;
        }
        return true;
    }
}

Python

class Trie:
    def __init__(self):
        self.nodes = [None for _ in range(26)]
        self.has_word = False;

    def insert(self, word: str) -> None:
        cur = self
        for ch in word:
            nex = ord(ch) - 97
            if cur.nodes[nex] is None:
                cur.nodes[nex] = Trie()
            cur = cur.nodes[nex]
        cur.has_word = True

    def search(self, word: str) -> bool:
        cur = self
        for ch in word:
            nex = ord(ch) - 97
            cur = cur.nodes[nex]
            if cur is None:
                return False
        return cur.has_word

    def startsWith(self, prefix: str) -> bool:
        cur = self
        for ch in prefix:
            nex = ord(ch) - 97
            cur = cur.nodes[nex]
            if cur is None:
                return False
        return True        
   nex = ord(ch) - 97
        cur = cur.nodes[nex]
        if cur is None:
            return False
    return True        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值