首页 >web前端 >js教程 >Trie(前缀树)简介

Trie(前缀树)简介

Patricia Arquette
Patricia Arquette原创
2025-01-15 06:26:43357浏览

Introduction to Trie (Prefix Tree)

Trie 是一种树状数据结构,用于高效存储和搜索字符串,特别是在自动完成、拼写检查和 IP 路由等应用程序中。


Trie 的关键属性:

  1. 节点:每个节点代表一个字符。
  2. Root:根节点为空,作为起点。
  3. 子节点:每个节点最多有 26 个子节点(小写英文字母)或更多,具体取决于字符集。
  4. 词尾标记:标记一些节点以指示词的结尾。

基本特里树操作:

1. 插入

插入单词需要遍历特里树并为不存在的字符创建新节点。

2. 搜索

搜索通过遍历单词的节点来检查单词是否存在于 trie 中。

3. 前缀搜索

这会检查 trie 中是否有任何单词以给定的前缀开头。


JavaScript 中基本 Trie 的实现:

class TrieNode {
    constructor() {
        this.children = {}; // Stores child nodes
        this.isEndOfWord = false; // Marks the end of a word
    }
}

class Trie {
    constructor() {
        this.root = new TrieNode();
    }

    // Insert a word
    insert(word) {
        let node = this.root;
        for (let char of word) {
            if (!node.children[char]) {
                node.children[char] = new TrieNode();
            }
            node = node.children[char];
        }
        node.isEndOfWord = true; // Mark the end of the word
    }

    // Search for a word
    search(word) {
        let node = this.root;
        for (let char of word) {
            if (!node.children[char]) {
                return false;
            }
            node = node.children[char];
        }
        return node.isEndOfWord;
    }

    // Check if any word starts with the given prefix
    startsWith(prefix) {
        let node = this.root;
        for (let char of prefix) {
            if (!node.children[char]) {
                return false;
            }
            node = node.children[char];
        }
        return true;
    }
}

// Example usage
const trie = new Trie();
trie.insert("apple");
console.log(trie.search("apple"));   // true
console.log(trie.search("app"));     // false
console.log(trie.startsWith("app")); // true
trie.insert("app");
console.log(trie.search("app"));     // true

高级 Trie 操作:

1. 删除单词

删除单词涉及递归方法,即删除不再需要的节点。

delete(word, node = this.root, depth = 0) {
    if (depth === word.length) {
        if (!node.isEndOfWord) return false; // Word doesn't exist
        node.isEndOfWord = false;
        return Object.keys(node.children).length === 0; // Check if node has children
    }

    const char = word[depth];
    if (!node.children[char]) return false;

    const shouldDeleteChild = this.delete(word, node.children[char], depth + 1);

    if (shouldDeleteChild) {
        delete node.children[char];
        return Object.keys(node.children).length === 0 && !node.isEndOfWord;
    }

    return false;
}

2. 计算带有前缀的单词

计算有多少个单词以给定前缀开头。

countWordsWithPrefix(prefix) {
    let node = this.root;
    for (let char of prefix) {
        if (!node.children[char]) return 0;
        node = node.children[char];
    }
    return this._countWords(node);
}

_countWords(node) {
    let count = node.isEndOfWord ? 1 : 0;
    for (let char in node.children) {
        count += this._countWords(node.children[char]);
    }
    return count;
}

3. 自动完成建议

给定前缀,返回以其开头的所有单词。

getWordsWithPrefix(prefix) {
    let node = this.root;
    for (let char of prefix) {
        if (!node.children[char]) return [];
        node = node.children[char];
    }
    return this._collectWords(node, prefix);
}

_collectWords(node, prefix) {
    let results = [];
    if (node.isEndOfWord) results.push(prefix);

    for (let char in node.children) {
        results = results.concat(this._collectWords(node.children[char], prefix + char));
    }

    return results;
}

时间复杂度:

  1. 插入:O(L)(L = 单词长度)
  2. 搜索:O(L)
  3. 前缀搜索:O(L)
  4. 删除:O(L)

特里树的应用:

  1. 自动完成系统(例如搜索栏、文本编辑器)。
  2. 拼写检查器
  3. IP 路由(最长前缀匹配)。
  4. 文字游戏(例如,Boggle)。
  5. DNA 序列匹配.

以上是Trie(前缀树)简介的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn