字典树
1 //----------用数组实现a -> z的字典树----------
2 //注:若next报错则用nxt等其他变量名
3 const int maxn = 100010;
4 const int charsize = 26; //字符集大小
5
6 //记录此节点的子节点编号(默认全是小写字母)
7 int next[maxn + 1][charsize];
8
9 //表示此编号节点是否为终止节点
10 bool isEnd[maxn + 1];
11
12 int root = 0;
13 int cnt = 0; //表示当前的节点编号数
14
15 //----------字典树的插入----------
16
17 //s为等待插入的字符串,1base,len为字符串长度
18 void insert(char s[], int len){
19 int now = 0; //当前在哪个节点上
20 for (int i = 1;i <= len;i++){ //遍历,没什么好说的
21 int x = s[i] - 'a'; //转成数字
22 if (!next[now][x]){ //如果当前节点没有子节点x,则创建之,并且给予编号
23 next[now][x] = ++cnt;
24 }
25 now = next[now][x]; //无论创建了新节点与否,都更新当前节点的位置
26 }
27 isEnd[now] = true; //最后的最后,把该字符串的最后一个字符的isEnd标记为true
28 return;
29 }
30
31 //----------字典树的查找----------
32
33 //实际上查找和插入的本质是相似的
34 //s为等待插入的字符串,1base,len为字符串长度
35 bool search(char s[], int len){
36 int now = 0; //和上面一样,记录当前在看的节点
37 for (int i = 1; i <= len;i++){ //遍历之
38 int x = s[i] - 'a'; //转成数字
39 if (!next[now][x]){ //如果当前节点没有子节点x,则直接返回false
40 return false;
41 }
42 now = next[now][x]; //如果没有return则更新当前节点位置,继续循环
43 }
44 return isEnd[now]; //最后进行判断最后一个字符是否是结束位置,返回即可
45 }
46
47 //----------字典树的删除----------
48
49 //其实Trie树需要删除数据的情况比较罕见
50 //这个时候我们需要记录每个树节点的"子树大小",这里的子树大小不同于一般的概念(一般的就是说子树有多少个节点)
51 //这里的子树大小指的是该节点的子树上有多少个真实存在的字符串(真实存在的意思就是必须结尾字符的isEnd是true)
52
53 //对于要删除的字符串,先用查找字符串的方式找到末尾,删除标记(isEnd)后回溯整条路径
54 //值得一提的是,如果路径上节点的子树大小为0,就可以直接删除这个节点
55
56
57
58
59 //----------用Struct存储字典树----------
60
61 const int maxn = 100010;
62 const int charsize = 26;
63
64 //-----简单写法-----
65
66 struct TreeNode{
67 int next[charsize];
68 bool isEnd;
69 } tree[maxn + 1];
70
71 //-----当字符集较大时-----
72
73 struct TreeNode{
74 unordered_map <char, int> next_map;
75 bool isEnd;
76 } tree[maxn + 1];
77
78 //-----指针-----
79
80 struct TreeNode{
81 TreeNode *next[charsize];
82 bool isEnd;
83 } *root;