字典树 (Trie)
Tries
约 16 分钟 · v15
字典树 Trie
cs-ds/trie · COMP25211 一句话定义
要又快又省地存一大堆字符串、还能秒判"某个开头是不是已存的词"——字典树(Trie)的招数是:不在节点里存整串,而是每条边代表一个字符,从根走下来的路径连起来才是字符串;再用一个 isEnd 标记说清"这条路径到这儿,是不是一个完整单词"。
2 模型 · 字符串怎么"逐字下落"
分两小步:第 1 步先用查词器弄懂"路径 = 字符串、isEnd 区分单词与前缀"这条核心;第 2 步看插入/查找时,cur 怎么沿着字符一格一格往下走。
字典里已存 cat · car · card · dog · do。输入一个词,它会从根逐字符往下走:每个字母若有对应的边就变绿、走通;走到末尾再看那个节点的 isEnd,给出三种结论之一
试试 car(是单词)、ca(只是前缀)、cab(路断了)、do(是单词,虽然它也是 dog 的前缀)。"能走通"只说明它是某些词的前缀;"是不是已存单词"完全由终点的 isEnd 决定。代码里这一步就是 cur = cur->child[s[i]-'a'],走完再看 cur->isEnd。
一个节点不存字符串,只存:①是不是某个词的结尾;②指向 26 个孩子(a~z)的指针,空位就是 NULL。
struct node { bool isEnd; // 这个节点是不是某个单词的结尾 struct node *child[26]; // 26 个孩子位,对应 a~z }; // 造一个新节点:还不是结尾,26 个孩子全空 struct node *newNode(void) { struct node *n = malloc(sizeof(struct node)); n->isEnd = false; // 必须显式置 false for (int i = 0; i < 26; i++) n->child[i] = NULL; return n; }
字符怎么变成孩子下标?c = s[i] - 'a':'a'→0、'b'→1、…、'z'→25。下面就来看 insert / search 怎么用它一行行往下走。
第 2 步 · 看代码一行行跑。右边是真实 C 代码,随动画逐行高亮。三个例子:插入会复用已有前缀、只在缺口处新建节点;查找的关键全在最后一行——走到了还不够,必须 isEnd 才算单词。点例子,再点 ▶ 慢慢看(建议 0.5×)。
Trie 插入 / 查找演示
3 核心要点 · 4 句人话看懂 Trie
每张卡片先用一句大白话说清"它到底在讲什么",再配最小例子。
c='x'-'a' 个位放"下一个字符是 x"的孩子,空位(NULL)=没这个分支。4 错误实验室 · 点一下亲眼看 bug
下面 4 个是写 Trie 最常翻车的坑——第 ① 个「漏查 isEnd」正是考试爱挖的「前缀误识别」。点击卡片,控制台会模拟运行效果。
5 即时小测 · 5 题 + 动手例题
这 5 题都卡在初学者最常错的点上——词数怎么数、前缀≠单词、插入新增几个节点、字符下标、为什么必须查 isEnd。最后到练习系统亲手写一遍 search。
读完这节,你应该明白:
Trie 把"一堆字符串"摊成一棵树:每条边一个字符,从根走下来的路径就是字符串,节点本身不存整串。靠 child[26](按 s[i]-'a' 索引)做到"下一个字符走哪"是 O(1);靠 共享前缀省空间、让查/插稳定 O(L)(与词数无关)。最关键、也最容易错的一条:能走通只说明它是某些词的前缀,必须看终点的 isEnd 才能断定"是不是一个已存单词"——漏查 isEnd 就是经典的"前缀误识别"。考试爱考数词数(=isEnd 节点数)、查找路径、插入新增节点数。它常用来做自动补全,也是除哈希表外存"键"的另一条路 ↓