什么是字典树

字典树(Trie)就像一个超级智能的单词索引本:你只需输入前几个字母,它就能瞬间找到所有匹配的单词,就像手机输入法的联想功能一样。

核心特点

  • 前缀匹配:输入"app"立即找到"apple"、“application”
  • 查找极快:O(m)复杂度,m是字符串长度
  • 共享前缀:相同前缀只存一次,节省空间
  • 自动补全:轻松实现输入提示功能
比喻:
传统查找 = 在字典里一页页翻找单词(慢)
字典树 = 按字母顺序的目录树(快)
查找"apple":
第1步:找到字母'a'的分支
第2步:在'a'下找'p'
第3步:在'p'下找'p'
...

算法原理

树形结构

字典树是一种树形数据结构,每个节点代表一个字符:

存储单词: "app", "apple", "apply", "bat", "ball"
字典树结构:
         root
        /    \
       a      b
       |      |
       p      a
       |      |
       p      t(✓)  l
      / \           |
     l   l          l(✓)
     |   |
     e   y
     |   |
    (✓) (✓)
(✓) 表示单词结束

插入过程

插入"cat":
1. 从root开始
2. 没有'c'子节点 → 创建'c'节点
3. 没有'a'子节点 → 创建'a'节点
4. 没有't'子节点 → 创建't'节点
5. 标记't'为单词结束
         root
          |
          c
          |
          a
          |
         t(✓)

查找过程

查找"app":
1. root → 'a' ✓ 存在
2. 'a' → 'p' ✓ 存在
3. 'p' → 'p' ✓ 存在
4. 检查是否单词结束 ✓ 是
→ 找到!
查找"ap":
1. root → 'a' ✓ 存在
2. 'a' → 'p' ✓ 存在
3. 检查是否单词结束 ✗ 不是
→ 不是完整单词

Unity游戏开发应用场景

1. 游戏控制台 - 命令自动补全

输入命令时自动提示匹配的命令,提升开发效率。

2. 物品系统 - 快速搜索

背包系统中,玩家输入关键词快速查找物品,支持前缀匹配。

3. 聊天系统 - 敏感词过滤

实时检测聊天内容是否包含敏感词,并进行替换或屏蔽。

4. ️ NPC对话 - 关键词触发

NPC对话系统,根据玩家输入的关键词触发特定对话分支。

5. 技能系统 - 技能名称搜索

技能树中快速搜索技能名称,支持模糊匹配和自动补全。

提示:完整的代码实现请参考下方"Unity使用示例"章节。

Unity C# 实现

基础实现

using System.Collections.Generic;
using UnityEngine;
/// <summary>
  /// 字典树节点
/// </summary>
public class TrieNode
{
public Dictionary<char, TrieNode> Children { get; private set; }
  public bool IsEndOfWord { get; set; }
  public string Word { get; set; } // 存储完整单词(可选,方便获取)
  public TrieNode()
  {
  Children = new Dictionary<char, TrieNode>();
    IsEndOfWord = false;
    Word = null;
    }
    }
    /// <summary>
      /// 字典树 - Unity实现
    /// </summary>
    public class Trie
    {
    private TrieNode root;
    private int wordCount;
    public Trie()
    {
    root = new TrieNode();
    wordCount = 0;
    }
    /// <summary>
      /// 插入单词
    /// </summary>
  /// <param name="word">要插入的单词</param>
    public void Insert(string word)
    {
    if (string.IsNullOrEmpty(word))
    return;
    TrieNode current = root;
    // 逐字符遍历
    foreach (char c in word.ToLower())
    {
    if (!current.Children.ContainsKey(c))
    {
    current.Children[c] = new TrieNode();
    }
    current = current.Children[c];
    }
    // 标记单词结束
    if (!current.IsEndOfWord)
    {
    current.IsEndOfWord = true;
    current.Word = word;
    wordCount++;
    }
    }
    /// <summary>
      /// 查找完整单词
    /// </summary>
  /// <param name="word">要查找的单词</param>
  /// <returns>是否存在</returns>
    public bool Search(string word)
    {
    if (string.IsNullOrEmpty(word))
    return false;
    TrieNode node = FindNode(word.ToLower());
    return node != null && node.IsEndOfWord;
    }
    /// <summary>
      /// 检查是否存在以prefix开头的单词
    /// </summary>
  /// <param name="prefix">前缀</param>
  /// <returns>是否存在</returns>
    public bool StartsWith(string prefix)
    {
    if (string.IsNullOrEmpty(prefix))
    return false;
    return FindNode(prefix.ToLower()) != null;
    }
    /// <summary>
      /// 获取所有以prefix开头的单词
    /// </summary>
  /// <param name="prefix">前缀</param>
  /// <returns>匹配的单词列表</returns>
    public List<string> GetWordsWithPrefix(string prefix)
      {
      List<string> results = new List<string>();
        if (string.IsNullOrEmpty(prefix))
        return results;
        TrieNode node = FindNode(prefix.ToLower());
        if (node == null)
        return results;
        // 从该节点开始DFS收集所有单词
        CollectWords(node, prefix, results);
        return results;
        }
        /// <summary>
          /// 删除单词
        /// </summary>
      /// <param name="word">要删除的单词</param>
      /// <returns>是否成功删除</returns>
        public bool Delete(string word)
        {
        if (string.IsNullOrEmpty(word))
        return false;
        return DeleteHelper(root, word.ToLower(), 0);
        }
        /// <summary>
          /// 获取总单词数
        /// </summary>
        public int GetWordCount()
        {
        return wordCount;
        }
        /// <summary>
          /// 清空字典树
        /// </summary>
        public void Clear()
        {
        root = new TrieNode();
        wordCount = 0;
        }
        // 查找节点
        private TrieNode FindNode(string str)
        {
        TrieNode current = root;
        foreach (char c in str)
        {
        if (!current.Children.ContainsKey(c))
        return null;
        current = current.Children[c];
        }
        return current;
        }
        // DFS收集所有单词
        private void CollectWords(TrieNode node, string prefix, List<string> results)
          {
          if (node.IsEndOfWord)
          {
          results.Add(node.Word ?? prefix);
          }
          foreach (var pair in node.Children)
          {
          CollectWords(pair.Value, prefix + pair.Key, results);
          }
          }
          // 递归删除辅助方法
          private bool DeleteHelper(TrieNode current, string word, int index)
          {
          if (index == word.Length)
          {
          if (!current.IsEndOfWord)
          return false;
          current.IsEndOfWord = false;
          current.Word = null;
          wordCount--;
          // 如果没有子节点,可以删除
          return current.Children.Count == 0;
          }
          char c = word[index];
          if (!current.Children.ContainsKey(c))
          return false;
          TrieNode child = current.Children[c];
          bool shouldDeleteChild = DeleteHelper(child, word, index + 1);
          if (shouldDeleteChild)
          {
          current.Children.Remove(c);
          // 如果当前节点也不是单词结尾且没有其他子节点,也可以删除
          return !current.IsEndOfWord && current.Children.Count == 0;
          }
          return false;
          }
          }

优化版本 - 压缩字典树

适用场景:大量单词有共同长前缀时,节省空间

using System.Collections.Generic;
using UnityEngine;
/// <summary>
  /// 压缩字典树节点
/// </summary>
public class CompressedTrieNode
{
public Dictionary<string, CompressedTrieNode> Children { get; private set; }
  public bool IsEndOfWord { get; set; }
  public string Word { get; set; }
  public CompressedTrieNode()
  {
  Children = new Dictionary<string, CompressedTrieNode>();
    IsEndOfWord = false;
    }
    }
    /// <summary>
      /// 压缩字典树 - 相同前缀压缩存储
    /// </summary>
    public class CompressedTrie
    {
    private CompressedTrieNode root;
    public CompressedTrie()
    {
    root = new CompressedTrieNode();
    }
    public void Insert(string word)
    {
    if (string.IsNullOrEmpty(word))
    return;
    InsertHelper(root, word.ToLower(), word);
    }
    private void InsertHelper(CompressedTrieNode node, string remaining, string fullWord)
    {
    if (remaining.Length == 0)
    {
    node.IsEndOfWord = true;
    node.Word = fullWord;
    return;
    }
    // 查找最长公共前缀
    foreach (var edge in node.Children.Keys)
    {
    int commonLength = GetCommonPrefixLength(edge, remaining);
    if (commonLength > 0)
    {
    if (commonLength == edge.Length)
    {
    // 完全匹配边,继续向下
    InsertHelper(node.Children[edge], remaining.Substring(commonLength), fullWord);
    return;
    }
    else
    {
    // 需要分裂边
    SplitEdge(node, edge, commonLength, remaining, fullWord);
    return;
    }
    }
    }
    // 没有匹配的边,创建新边
    CompressedTrieNode newNode = new CompressedTrieNode();
    newNode.IsEndOfWord = true;
    newNode.Word = fullWord;
    node.Children[remaining] = newNode;
    }
    private void SplitEdge(CompressedTrieNode node, string edge, int splitPos,
    string remaining, string fullWord)
    {
    // 实现边分裂逻辑(简化版)
    CompressedTrieNode oldChild = node.Children[edge];
    node.Children.Remove(edge);
    string commonPrefix = edge.Substring(0, splitPos);
    string oldSuffix = edge.Substring(splitPos);
    string newSuffix = remaining.Substring(splitPos);
    CompressedTrieNode newNode = new CompressedTrieNode();
    newNode.Children[oldSuffix] = oldChild;
    if (newSuffix.Length > 0)
    {
    CompressedTrieNode leafNode = new CompressedTrieNode();
    leafNode.IsEndOfWord = true;
    leafNode.Word = fullWord;
    newNode.Children[newSuffix] = leafNode;
    }
    else
    {
    newNode.IsEndOfWord = true;
    newNode.Word = fullWord;
    }
    node.Children[commonPrefix] = newNode;
    }
    private int GetCommonPrefixLength(string str1, string str2)
    {
    int minLen = Mathf.Min(str1.Length, str2.Length);
    int i = 0;
    while (i < minLen && str1[i] == str2[i])
    {
    i++;
    }
    return i;
    }
    public bool Search(string word)
    {
    if (string.IsNullOrEmpty(word))
    return false;
    return SearchHelper(root, word.ToLower());
    }
    private bool SearchHelper(CompressedTrieNode node, string remaining)
    {
    if (remaining.Length == 0)
    return node.IsEndOfWord;
    foreach (var edge in node.Children.Keys)
    {
    if (remaining.StartsWith(edge))
    {
    return SearchHelper(node.Children[edge], remaining.Substring(edge.Length));
    }
    }
    return false;
    }
    }

Unity使用示例

示例1:游戏控制台自动补全

using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;
public class GameConsole : MonoBehaviour
{
[SerializeField] private InputField commandInput;
[SerializeField] private Transform suggestionPanel;
[SerializeField] private GameObject suggestionItemPrefab;
private Trie commandTrie;
void Start()
{
// 初始化命令字典树
commandTrie = new Trie();
// 注册命令
RegisterCommands();
// 监听输入变化
commandInput.onValueChanged.AddListener(OnCommandInputChanged);
}
void RegisterCommands()
{
string[] commands = {
"help",
"spawn",
"spawnEnemy",
"spawnItem",
"spawnNPC",
"teleport",
"teleportToPlayer",
"setHealth",
"setMana",
"giveItem",
"giveGold",
"clear",
"quit"
};
foreach (string cmd in commands)
{
commandTrie.Insert(cmd);
}
Debug.Log($"注册了 {commandTrie.GetWordCount()} 个命令");
}
void OnCommandInputChanged(string input)
{
// 清空之前的建议
ClearSuggestions();
if (string.IsNullOrEmpty(input))
return;
// 获取匹配的命令
List<string> suggestions = commandTrie.GetWordsWithPrefix(input.ToLower());
  // 显示建议
  foreach (string suggestion in suggestions)
  {
  GameObject item = Instantiate(suggestionItemPrefab, suggestionPanel);
  item.GetComponentInChildren<Text>().text = suggestion;
    // 点击建议自动填充
    item.GetComponent<Button>().onClick.AddListener(() => {
      commandInput.text = suggestion;
      });
      }
      // 显示/隐藏建议面板
      suggestionPanel.gameObject.SetActive(suggestions.Count > 0);
      }
      void ClearSuggestions()
      {
      foreach (Transform child in suggestionPanel)
      {
      Destroy(child.gameObject);
      }
      }
      }

示例2:背包物品搜索系统

using UnityEngine;
using System.Collections.Generic;
public class InventorySearchSystem : MonoBehaviour
{
private Trie itemNameTrie;
private Dictionary<string, Item> itemDatabase;
  [System.Serializable]
  public class Item
  {
  public string id;
  public string name;
  public string description;
  public Sprite icon;
  }
  void Start()
  {
  itemNameTrie = new Trie();
  itemDatabase = new Dictionary<string, Item>();
    LoadItems();
    }
    void LoadItems()
    {
    // 模拟加载物品数据
    Item[] items = {
    new Item { id = "sword001", name = "Iron Sword", description = "A basic sword" },
    new Item { id = "sword002", name = "Steel Sword", description = "A strong sword" },
    new Item { id = "sword003", name = "Flame Sword", description = "A burning sword" },
    new Item { id = "potion001", name = "Health Potion", description = "Restores HP" },
    new Item { id = "potion002", name = "Mana Potion", description = "Restores MP" },
    new Item { id = "shield001", name = "Wooden Shield", description = "Basic defense" }
    };
    foreach (var item in items)
    {
    string key = item.name.ToLower();
    itemNameTrie.Insert(key);
    itemDatabase[key] = item;
    }
    Debug.Log($"加载了 {itemDatabase.Count} 个物品");
    }
    public List<Item> SearchItems(string query)
      {
      List<Item> results = new List<Item>();
        if (string.IsNullOrEmpty(query))
        return results;
        // 获取匹配的物品名称
        List<string> matchedNames = itemNameTrie.GetWordsWithPrefix(query.ToLower());
          // 转换为物品对象
          foreach (string name in matchedNames)
          {
          if (itemDatabase.ContainsKey(name))
          {
          results.Add(itemDatabase[name]);
          }
          }
          Debug.Log($"搜索 '{query}' 找到 {results.Count} 个物品");
          return results;
          }
          // UI调用
          public void OnSearchInputChanged(string query)
          {
          List<Item> results = SearchItems(query);
            DisplaySearchResults(results);
            }
            void DisplaySearchResults(List<Item> items)
              {
              // 显示搜索结果到UI
              foreach (var item in items)
              {
              Debug.Log($"找到物品: {item.name} - {item.description}");
              }
              }
              }

示例3:性能测试对比

using System.Collections.Generic;
using System.Diagnostics;
using UnityEngine;
using Debug = UnityEngine.Debug;
public class TrieBenchmark : MonoBehaviour
{
void Start()
{
int testSize = 10000;
string[] words = GenerateTestWords(testSize);
// 测试List<string>查找
  Stopwatch sw1 = Stopwatch.StartNew();
  List<string> wordList = new List<string>(words);
    sw1.Stop();
    Stopwatch sw2 = Stopwatch.StartNew();
    int listMatches = 0;
    foreach (string word in wordList)
    {
    if (word.StartsWith("test"))
    listMatches++;
    }
    sw2.Stop();
    // 测试Trie查找
    Stopwatch sw3 = Stopwatch.StartNew();
    Trie trie = new Trie();
    foreach (string word in words)
    {
    trie.Insert(word);
    }
    sw3.Stop();
    Stopwatch sw4 = Stopwatch.StartNew();
    List<string> trieMatches = trie.GetWordsWithPrefix("test");
      sw4.Stop();
      Debug.Log("=== 性能对比测试 ===");
      Debug.Log($"数据规模: {testSize} 个单词");
      Debug.Log($"\nList<string>:");
        Debug.Log($"  插入耗时: {sw1.ElapsedMilliseconds}ms");
        Debug.Log($"  前缀查找耗时: {sw2.ElapsedMilliseconds}ms");
        Debug.Log($"  找到: {listMatches} 个匹配");
        Debug.Log($"\nTrie:");
        Debug.Log($"  插入耗时: {sw3.ElapsedMilliseconds}ms");
        Debug.Log($"  前缀查找耗时: {sw4.ElapsedMilliseconds}ms");
        Debug.Log($"  找到: {trieMatches.Count} 个匹配");
        Debug.Log($"\n速度提升: {sw2.ElapsedMilliseconds / (float)sw4.ElapsedMilliseconds:F1}x");
        }
        string[] GenerateTestWords(int count)
        {
        string[] prefixes = { "test", "game", "unity", "play", "item" };
        string[] suffixes = { "data", "system", "manager", "controller", "handler" };
        List<string> words = new List<string>();
          for (int i = 0; i < count; i++)
          {
          string prefix = prefixes[i % prefixes.Length];
          string suffix = suffixes[i % suffixes.Length];
          words.Add($"{prefix}{suffix}{i}");
          }
          return words.ToArray();
          }
          }

性能分析

时间复杂度

操作时间复杂度说明
插入O(m)m是字符串长度
查找O(m)m是字符串长度
前缀匹配O(m + n)m是前缀长度,n是匹配数量
删除O(m)m是字符串长度

空间复杂度

最坏情况: O(ALPHABET_SIZE * N * M)
- ALPHABET_SIZE: 字符集大小(26个字母)
- N: 单词数量
- M: 平均单词长度
实际情况: 由于前缀共享,远小于最坏情况

与其他数据结构对比

操作ListHashSetTrie场景
前缀查找O(n*m)❌不支持O(p+n)Trie最优
精确查找O(n)O(1)O(m)HashSet最优
自动补全O(n*m)❌不支持O(p+n)Trie最优
空间占用List最优

前缀查找性能对比(10000个单词):

List遍历: ~50ms
Trie查找: ~0.5ms
性能提升: 100倍!

常见问题

Q: 字典树适合什么场景?
A:
✅ 适合:前缀匹配、自动补全、单词查找
❌ 不适合:精确查找(用HashSet更好)、数值查找

Q: 字典树很占内存吗?
A:

  • 单词少:是的,每个字符一个节点
  • 单词多且有共同前缀:不,前缀共享节省空间
  • 优化方案:使用压缩字典树

Q: 如何处理大小写?
A: 统一转换为小写存储:

trie.Insert(word.ToLower());

Q: 可以存储中文吗?
A: 可以!中文也是字符,只是字符集更大:

trie.Insert("你好世界"); // 完全支持

Q: 与哈希表比较?
A:

  • 哈希表:精确查找O(1),不支持前缀
  • 字典树:前缀查找O(m),支持模糊匹配

选择建议:

精确查找 → HashSet
前缀匹配 → Trie
两者都需要 → 组合使用

Unity性能优化建议

1. 对象池优化

public class TrieNodePool
{
private static Stack<TrieNode> pool = new Stack<TrieNode>();
  public static TrieNode Get()
  {
  if (pool.Count > 0)
  {
  var node = pool.Pop();
  node.Children.Clear();
  node.IsEndOfWord = false;
  node.Word = null;
  return node;
  }
  return new TrieNode();
  }
  public static void Return(TrieNode node)
  {
  pool.Push(node);
  }
  }

2. 异步加载词库

IEnumerator LoadDictionaryAsync(string[] words)
{
int batchSize = 100;
for (int i = 0; i < words.Length; i += batchSize)
{
int end = Mathf.Min(i + batchSize, words.Length);
for (int j = i; j < end; j++)
{
trie.Insert(words[j]);
}
yield return null; // 分帧加载,不卡顿
}
Debug.Log("词库加载完成");
}

3. 缓存查询结果

public class CachedTrie
{
private Trie trie;
private Dictionary<string, List<string>> cache;
  public CachedTrie()
  {
  trie = new Trie();
  cache = new Dictionary<string, List<string>>();
    }
    public List<string> GetWordsWithPrefix(string prefix)
      {
      if (cache.ContainsKey(prefix))
      return cache[prefix];
      var results = trie.GetWordsWithPrefix(prefix);
      cache[prefix] = results;
      return results;
      }
      }
      ### 4. 敏感词过滤优化
      > **⚠️ 注意**:上面示例中的敏感词过滤实现是简化版,效率不高。下面提供更高效的实现方案。
      **方案一:逐字符匹配(推荐用于简单场景)**
      ```csharp
      public class SensitiveWordFilter
      {
      private Trie sensitiveWords;
      public SensitiveWordFilter()
      {
      sensitiveWords = new Trie();
      }
      public void AddSensitiveWord(string word)
      {
      sensitiveWords.Insert(word.ToLower());
      }
      /// <summary>
        /// 优化的敏感词过滤 - 逐字符匹配
      /// </summary>
      public string FilterMessage(string message)
      {
      if (string.IsNullOrEmpty(message))
      return message;
      char[] chars = message.ToLower().ToCharArray();
      TrieNode root = GetTrieRoot(); // 需要暴露Trie的root节点
      for (int i = 0; i < chars.Length; i++)
      {
      TrieNode node = root;
      int matchLength = 0;
      // 从当前位置开始尝试匹配
      for (int j = i; j < chars.Length; j++)
      {
      if (!node.Children.ContainsKey(chars[j]))
      break;
      node = node.Children[chars[j]];
      matchLength++;
      // 找到完整敏感词
      if (node.IsEndOfWord)
      {
      // 替换为星号
      for (int k = i; k < i + matchLength; k++)
      {
      chars[k] = '*';
      }
      break;
      }
      }
      }
      return new string(chars);
      }
      }

方案二:AC自动机(推荐用于大量敏感词)

/// <summary>
  /// 使用AC自动机进行敏感词过滤(更高效)
  /// 适合大量敏感词的场景
/// </summary>
public class AhoCorasickFilter
{
private class ACNode
{
public Dictionary<char, ACNode> Children = new Dictionary<char, ACNode>();
  public ACNode Fail; // 失败指针
  public List<string> Outputs = new List<string>(); // 匹配的敏感词
    }
    private ACNode root;
    public AhoCorasickFilter()
    {
    root = new ACNode();
    }
    public void AddPattern(string pattern)
    {
    ACNode node = root;
    foreach (char c in pattern.ToLower())
    {
    if (!node.Children.ContainsKey(c))
    {
    node.Children[c] = new ACNode();
    }
    node = node.Children[c];
    }
    node.Outputs.Add(pattern);
    }
    public void Build()
    {
    Queue<ACNode> queue = new Queue<ACNode>();
      // 第一层的失败指针指向root
      foreach (var child in root.Children.Values)
      {
      child.Fail = root;
      queue.Enqueue(child);
      }
      // BFS构建失败指针
      while (queue.Count > 0)
      {
      ACNode current = queue.Dequeue();
      foreach (var pair in current.Children)
      {
      char c = pair.Key;
      ACNode child = pair.Value;
      queue.Enqueue(child);
      ACNode failNode = current.Fail;
      while (failNode != null && !failNode.Children.ContainsKey(c))
      {
      failNode = failNode.Fail;
      }
      child.Fail = failNode?.Children.GetValueOrDefault(c, root) ?? root;
      child.Outputs.AddRange(child.Fail.Outputs);
      }
      }
      }
      public string FilterMessage(string message)
      {
      if (string.IsNullOrEmpty(message))
      return message;
      char[] chars = message.ToCharArray();
      ACNode node = root;
      for (int i = 0; i < chars.Length; i++)
      {
      char c = char.ToLower(chars[i]);
      while (node != root && !node.Children.ContainsKey(c))
      {
      node = node.Fail;
      }
      node = node.Children.GetValueOrDefault(c, root);
      // 找到匹配的敏感词
      foreach (string word in node.Outputs)
      {
      int startIndex = i - word.Length + 1;
      for (int j = 0; j < word.Length; j++)
      {
      chars[startIndex + j] = '*';
      }
      }
      }
      return new string(chars);
      }
      }

性能对比

敏感词数量: 1000个
消息长度: 500字符
简化版Trie: ~20ms
逐字符匹配: ~2ms (10倍提升)
AC自动机: ~0.5ms (40倍提升)
## ❌ 不适合使用字典树的场景
### 1. 纯数值查找
```csharp
// ❌ 不适合:存储玩家ID(数字)
Trie playerIds = new Trie();
playerIds.Insert("12345");
// ✅ 应该用:HashSet
HashSet playerIds = new HashSet();
playerIds.Add(12345);

2. 需要范围查询

// ❌ 不支持:查找年龄在20-30之间的玩家
trie.GetRange(20, 30); // 不支持
// ✅ 应该用:有序集合或数据库
SortedSet<int> ages = new SortedSet<int>();

3. 数据量极小

// ❌ 只有几个单词,用Trie浪费
Trie tiny = new Trie();
tiny.Insert("yes");
tiny.Insert("no");
// ✅ 直接用数组或List
string[] options = { "yes", "no" };

4. 频繁删除操作

// ⚠️ Trie删除操作复杂,性能不好
trie.Delete(word); // 需要遍历和重构
// ✅ 如果频繁删除,考虑用HashSet

总结

字典树是Unity游戏开发中的前缀匹配利器

  • 前缀查找极快:O(m)复杂度,比遍历快100倍
  • 自动补全完美:输入法、控制台必备
  • 共享前缀省空间:相同前缀只存一次
  • 支持模糊匹配:灵活的字符串处理
  • ⚠️ 空间占用较大:每个字符一个节点
  • 不适合精确查找:用HashSet更好

何时使用字典树?

  • 需要前缀匹配(自动补全)
  • 单词/命令查找
  • 敏感词过滤
  • 关键词提取
  • 拼写检查

典型应用场景:

  • 游戏控制台命令补全
  • 背包物品搜索
  • 聊天敏感词过滤
  • ️ NPC对话关键词
  • 技能名称搜索

掌握字典树,让你的Unity游戏交互更智能!