c++ trie树

概念

Trie(也叫前缀树或字典树)是一种树形数据结构,主要用于快速检索字符串集合中的前缀匹配,常见于词典、自动补全、IP 路由等场景。

特点

  • 共享前缀:Trie 树可以让多个字符串共用相同的前缀路径,从而节省空间;
  • 高效查询:Trie 的查找和插入操作的时间复杂度为 O(m),其中 m 是字符串的长度;
  • 动态增长:可以随时插入新单词,并适应大规模数据;
  • 支持前缀匹配:能够快速检查是否存在以某个字符串为前缀的单词,这在自动补全系统中非常有用;

示意图

用 Trie 树存储以下单词:

  • apple
  • app
  • application
  • banana
  • bat
Root
 ├── a
 │   └── p
 │       └── p (end) 
 │           ├── l ─── e (end)
 │           └── l ─── i ─── c ─── a ─── t ─── i ─── o ─── n (end)
 └── b
     ├── a ─── n ─── a ─── n ─── a (end)
     └── a ─── t (end)

常用操作

插入操作

  1. 从根节点开始遍历字符串的每个字符;
  2. 如果当前字符不存在于子节点中,则创建一个新节点;
  3. 当所有字符插入完成时,将最后一个节点标记为单词结束

查找操作

  1. 从根节点开始逐字符遍历;
  2. 如果所有字符都匹配,且最后节点标记为单词结束,则说明该单词存在;

前缀匹配(StartsWith)操作

  1. 从根节点逐字符匹配,判断给定前缀是否存在于树中;

优缺点

优点

  • 快速检索:查找、插入和前缀匹配的效率高,复杂度为 O(m)。
  • 支持前缀匹配查询:适合实现搜索引擎的自动补全功能。
  • 无需额外的哈希函数:与哈希表相比,Trie 不依赖于哈希函数,避免哈希冲突。

缺点

  • 空间开销较大:每个节点都需要存储子节点,若字符串过长或字符种类多,可能导致大量空间占用。
  • 存储的字符串种类有限:若字符集过于庞大(如UTF-8编码),Trie 的空间消耗会变得更高。

时间复杂度分析

  • 插入(Insert)O(m),其中m是字符串的长度。
  • 查找(Search)O(m)
  • 前缀匹配(StartsWith)O(m)

代码实现(c++)

#include <iostream>
#include <unordered_map>
#include <memory>
using namespace std;

class TrieNode {
public:
    std::unordered_map<char, std::unique_ptr<TrieNode>> children;  // 子节点
    bool isEndOfWord = false;  // 标记是否为单词的结束

    TrieNode() = default;  // 默认构造函数
};

class Trie {
private:
    std::unique_ptr<TrieNode> root;  // 根节点

public:
    Trie() {
        root = std::make_unique<TrieNode>();
    }

    // 插入一个字符串
    void insert(const string& word) {
        TrieNode* node = root.get();
        for (char c : word) {
            if (!node->children[c]) {
                node->children[c] = std::make_unique<TrieNode>();
            }
            node = node->children[c].get();
        }
        node->isEndOfWord = true;
    }

    // 查找一个字符串是否存在于 Trie 中
    bool search(const string& word) const {
        TrieNode* node = root.get();
        for (char c : word) {
            if (!node->children.count(c)) {
                return false;
            }
            node = node->children[c].get();
        }
        return node->isEndOfWord;
    }

    // 判断是否存在以给定前缀开头的字符串
    bool startsWith(const string& prefix) const {
        TrieNode* node = root.get();
        for (char c : prefix) {
            if (!node->children.count(c)) {
                return false;
            }
            node = node->children[c].get();
        }
        return true;
    }
};

int main() {
    Trie trie;

    // 插入单词
    trie.insert("apple");
    trie.insert("app");
    trie.insert("application");
    trie.insert("banana");
    trie.insert("bat");

    // 查找单词
    cout << boolalpha << trie.search("apple") << endl;  // true
    cout << trie.search("app") << endl;                 // true
    cout << trie.search("appl") << endl;                // false

    // 前缀匹配
    cout << trie.startsWith("app") << endl;             // true
    cout << trie.startsWith("ban") << endl;             // true
    cout << trie.startsWith("cat") << endl;             // false

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值