trie 前缀树 实现

前缀树Trie

什么是前缀树

前缀树(Trie),也称为字典树或单词查找树,是一种用于高效存储和检索字符串集合的数据结构,特别是用于字符串集合的前缀查询操作。前缀树非常适合处理字符串的前缀匹配问题,如自动补全、拼写检查和单词搜索等。

前缀树(Trie)的基本特点

  1. 节点表示字符
    • 每个节点表示一个字符,根节点通常不代表任何字符(可以认为是一个空字符)。
    • 从根节点到某一节点的路径上的字符序列表示一个字符串的前缀。
  2. 边连接字符
    • 从一个节点到它的子节点的边表示该节点字符后接的下一个字符。
    • 边上的字符决定了从当前节点到子节点的路径。
  3. 存储终止标记
    • 节点通常包含一个布尔值(或其他标记)来表示从根节点到该节点的路径是否构成一个有效的单词(终止标记)。

前缀树的主要操作

  1. 插入字符串
    • 从根节点开始,根据字符串中的每个字符,沿着现有的路径或创建新的节点,直到字符串的最后一个字符。
    • 在最后一个字符的节点处标记该路径为一个完整的单词。
  2. 查找字符串
    • 从根节点开始,按照字符串中的每个字符遍历路径。
    • 如果能找到完整的路径且路径上的节点都存在,那么该字符串存在于前缀树中。
  3. 前缀匹配
    • 与查找字符串类似,但只需要找到前缀路径,不需要是完整的单词路径。
    • 可以用来实现自动补全或查找所有以某一前缀开头的单词。

前缀树的示例

假设我们要构建一个包含单词 “cat”, “car”, “dog”, “dot” 的前缀树:

       (root)
        /   \
       c     d
      / \   / \
     a   a o   o
    /     \   \
   t       r   g
           \
            t

前缀树的优点

  1. 高效的前缀查询:能够快速找到具有相同前缀的所有单词。
  2. 节省空间:共享前缀的单词只存储一次,共用节点。

代码实现

#include <vector>
#include <string>

using namespace std;
class Trie {
private:
    vector<Trie*> children; // 子节点数组
    bool isEnd; // 标记当前节点是否为单词的结束节点

    // 在 Trie 树中搜索以 prefix 为前缀的节点
    Trie* searchPrefix(string prefix) 
    {
        Trie* node = this; // 从根节点开始搜索
        for (char ch : prefix)  // 遍历前缀字符串的每个字符
        {
            ch -= 'a'; // 将字符转换为索引值
            if (node->children[ch] == nullptr)  // 如果当前字符的子节点为空,说明前缀不存在
            {
                return nullptr;
            }
            node = node->children[ch]; // 继续向下搜索
        }
        return node; // 返回以 prefix 为前缀的节点
    }

public:
    // 构造函数,初始化 Trie 树的根节点和结束标志
    Trie() : children(26), isEnd(false) {}

    // 向 Trie 树中插入一个单词
    void insert(string word) 
    {
        Trie* node = this; // 从根节点开始插入
        for (char ch : word) // 遍历单词的每个字符
        { 
            ch -= 'a'; // 将字符转换为索引值
            if (node->children[ch] == nullptr)   如果当前字符的子节点为空,创建新节点
            { 
                node->children[ch] = new Trie();
            }
            node = node->children[ch]; // 继续向下插入
        }
        node->isEnd = true; // 设置当前节点为单词的结束节点
    }

    // 搜索 Trie 树中是否存在单词 word
    bool search(string word) 
    {
        Trie* node = this->searchPrefix(word); // 先搜索以 word 为前缀的节点
        return node != nullptr && node->isEnd; // 如果节点存在且是单词的结束节点,则返回 true
    }

    // 判断 Trie 树中是否存在以 prefix 为前缀的单词
    bool startsWith(string prefix) 
    {
        return this->searchPrefix(prefix) != nullptr; // 直接调用 searchPrefix 函数判断前缀是否存在
    }
};

/**
 * Your Trie object will be instantiated and called as such:
 * Trie* obj = new Trie();
 * obj->insert(word);
 * bool param_2 = obj->search(word);
 * bool param_3 = obj->startsWith(prefix);
 */

前缀树可以解决什么问题

前缀树(Trie)是一种非常有用的数据结构,可以解决以下几类问题:

  1. 字符串的快速搜索:前缀树能够高效地存储大量字符串,并且可以快速查找特定的字符串是否存在于集合中。这使得前缀树在搜索引擎、拼写检查器和自动补全等应用中非常有用。
  2. 自动补全和预测输入:利用前缀树可以实现快速的自动补全功能。例如,当用户输入一个前缀时,前缀树可以快速找到所有以该前缀开头的单词,从而为用户提供可能的选项。
  3. 拼写检查:前缀树可以用于检查单词的拼写是否正确。通过在前缀树中搜索输入单词的所有可能前缀,可以判断输入单词是否存在于字典中。
  4. 单词频率统计:前缀树可以用于统计文本中单词的出现频率。通过在前缀树中插入单词,并在每个单词节点上维护一个计数器,可以快速地计算出每个单词出现的次数。
  5. 前缀匹配:前缀树可以用于快速查找具有特定前缀的所有字符串。这对于查找电话号码、IP 地址或文件路径等具有特定前缀的条目非常有用。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值