http://blog.csdn.net/wyg1997/article/details/52121597

其实动态建树和静态建树都一样,只是动态建树省空间费时间,静态建树省时间费空间。

那么如果碰上数据很大的题的时候,还是选择静态建树吧,毕竟内存没有那么容易超。

那下面先说动态建树吧:

变量:

[cpp] view plaincopy print?
  1. struct Trie
  2. {
  3. Trie *next[10];
  4. int v;
  5. void init()
  6. {
  7. v = 0;
  8. for (int i = 0 ; i <= 9 ; i++)
  9. next[i] = NULL;
  10. }
  11. };
  12. Trie *root;

next[] 指针数组指向下一个节点。数组大小根据题目改变,例如,题目要求只有小写字母,那么开26就行了;如果包括大写,那么开52,如果还有数字,那就是62(一般包括数字的话,个人感觉树的规模不会建的太大,要不就出事了)。

变量v的含义非常灵活,可以表示当前字母被共享使用了多少次,也可以变成bool型表示一个单词的结束。这个要就题论题,不能太拘泥模板。

*root 表示指向根节点的指针,每次查询要先从根节点(不包括任何字母)开始。

初始化:

[cpp] view plaincopy print?
  1. root = (Trie *)malloc(sizeof(Trie));
  2. root->init();

第一行代码给 *root 指向的结构体开辟空间,第二行初始化root。

插入字符串:

[cpp] view plaincopy print?
  1. void insert(char *s)        //字符串
  2. {
  3. int l = strlen(s);
  4. Trie *p = root , *q;
  5. for (int i = 0 ; i < l ; i++)
  6. {
  7. int id = idx(s[i]);
  8. if (p->next[id] == NULL)
  9. {
  10. q = (Trie *)malloc(sizeof(Trie));       //开新指针
  11. q->init();
  12. p->next[id] = q;
  13. }
  14. p = p->next[id];
  15. p->v++;
  16. }
  17. }

思路大概就是,从字符串中依次取字符,如果树的枝叶有这个字符,那么就顺着这个枝叶对下一个字符进行操作,如果不存在,就再开一个叶子存这个字母。

注意:我这里的v的意思是这个位置的字母被多少字符串共享,其他使用要就题来改变。

查找操作:

[cpp] view plaincopy print?
  1. bool find(char *s)
  2. {
  3. int l = strlen(s);
  4. Trie *p = &tree[0];
  5. for (int i = 0 ; i < l ; i++)
  6. {
  7. int id = idx(s[i]);
  8. if (p->next[id] == NULL)     //没有这个单词
  9. return false;
  10. p = p->next[id];
  11. }
  12. if (p->word)
  13. return true;
  14. return false;       //如果有些单词只是 "路过" 也不算
  15. }

PS:这时候的word变量代替了之前的变量v,表示这个位置是否形成了单词。

这个函数的用法是查询一个单词是否出现过。如果插入操作看懂了,这个应该不难,就不细讲了。

查找最小前缀并输出:

[cpp] view plaincopy print?
  1. void min_permix(char s[][22],int x)     //查询最小前缀
  2. {
  3. printf ("%s ",s[x]);
  4. int l = strlen(s[x]);
  5. Trie *p = root;
  6. for (int i = 0 ; i < l ; i++)
  7. {
  8. printf ("%c",s[x][i]);
  9. int id = idx(s[x][i]);
  10. p = p->next[id];
  11. if (p->v == 1)       //如果字母单独出现说明已经出现最小前缀了,结束
  12. break;
  13. }
  14. printf ("\n");
  15. }

这个也应该不难理解了。

释放内存:(有些题需要把结构体开辟的内存释放掉,要不会MLE)

[cpp] view plaincopy print?
  1. void del(Trie *root)        //不释放内存的话会MLE
  2. {
  3. for (int i = 0 ; i < 10 ; i++)
  4. {
  5. if (root->next[i] != NULL)
  6. del(root->next[i]);
  7. }
  8. free(root);
  9. }

使用free函数+dfs释放内存。

然后说一下静态储存:

[cpp] view plaincopy print?
  1. struct Trie
  2. {
  3. Trie *next[10];
  4. int v;
  5. void init()
  6. {
  7. v = 0;
  8. for (int i = 0 ; i <= 9 ; i++)
  9. next[i] = NULL;
  10. }
  11. }tree[1<<16];
  12. int ant;

这个时候要把tree开的足够大,把你这棵树可能出现的最大枝叶树全部包括。

ant这个变量是动态的,不断往后开新的结构体来储存枝叶。(这一个不懂可以看一下下面的操作)(使用前记得初始化为1,而把tree[ 0 ] 作为根节点)

插入操作:

[cpp] view plaincopy print?
  1. void insert(char *s)
  2. {
  3. int l = strlen(s);
  4. Trie *p = &tree[0], *q;     //tree[0]为根节点
  5. for (int i = 0 ; i < l ; i++)
  6. {
  7. int id = idx(s[i]);
  8. if (p->next[id] == NULL)
  9. {
  10. q = &tree[ant++];
  11. p->next[id] = q;
  12. }
  13. p = p->next[id];
  14. }
  15. p->v = -1;       //这个-1表示一个字符串已经结束
  16. }

然后这个插入操作就不难理解了,其他操作类似动态的字典树,就不再一一码了。

然后贴一个大代码:

动态:(查找最小前缀)

[cpp] view plaincopy print?
  1. #include <cstdio>
  2. #include <cstring>
  3. #include <algorithm>
  4. using namespace std;
  5. #define CLR(a,b) memset(a,b,sizeof(a))
  6. #define INF 0x3f3f3f3f
  7. struct Trie
  8. {
  9. Trie *next[26];
  10. int v;
  11. void init()
  12. {
  13. v = 0;
  14. for (int i = 0 ; i < 26 ; i++)
  15. next[i] = NULL;
  16. }
  17. };
  18. Trie *root;
  19. int idx(char c)
  20. {
  21. return c - 'a';
  22. }
  23. void insert(char s[][22],int x)
  24. {
  25. int l = strlen(s[x]);
  26. Trie *p = root , *q;
  27. for (int i = 0 ; i < l ; i++)
  28. {
  29. int id = idx(s[x][i]);
  30. if (p->next[id] == NULL)
  31. {
  32. q = (Trie *)malloc(sizeof(Trie));       //开新指针
  33. q->init();
  34. p->next[id] = q;
  35. }
  36. p = p->next[id];
  37. p->v++;
  38. }
  39. }
  40. void min_permix(char s[][22],int x)     //查询最小前缀
  41. {
  42. printf ("%s ",s[x]);
  43. int l = strlen(s[x]);
  44. Trie *p = root;
  45. for (int i = 0 ; i < l ; i++)
  46. {
  47. printf ("%c",s[x][i]);
  48. int id = idx(s[x][i]);
  49. p = p->next[id];
  50. if (p->v == 1)       //如果字母单独出现说明已经出现最小前缀了,结束
  51. break;
  52. }
  53. printf ("\n");
  54. }
  55. int main()
  56. {
  57. char s[1011][22];
  58. int ant = 0;
  59. root = (Trie *)malloc(sizeof(Trie));
  60. root->init();
  61. while (~scanf ("%s",s[ant++]))
  62. insert(s,ant-1);
  63. for (int i = 0 ; i < ant ; i++)
  64. min_permix(s , i);
  65. return 0;
  66. }

静态:(查找某个字符串是否可以由已知的两个字符串拼接而成)

[cpp] view plaincopy print?
  1. #include <cstdio>
  2. #include <cstring>
  3. #include <algorithm>
  4. using namespace std;
  5. #define CLR(a,b) memset(a,b,sizeof(a))
  6. #define INF 0x3f3f3f3f
  7. #define idx(x) (x-'a')
  8. struct Trie
  9. {
  10. Trie *next[26];
  11. bool word;
  12. void clear()
  13. {
  14. for (int i = 0 ; i < 26 ; i++)
  15. next[i] = NULL;
  16. word = false;
  17. }
  18. }tree[100000];
  19. int ant;
  20. void insert(char *s)
  21. {
  22. int l = strlen(s);
  23. Trie *p = &tree[0] , *q;
  24. for (int i = 0 ; i < l ; i++)
  25. {
  26. int id = idx(s[i]);
  27. if (p->next[id] == NULL)
  28. {
  29. q = &tree[ant++];
  30. q->clear();
  31. p->next[id] = q;
  32. }
  33. p = p->next[id];
  34. }
  35. p->word = true;
  36. }
  37. bool find(char *s)
  38. {
  39. int l = strlen(s);
  40. Trie *p = &tree[0];
  41. for (int i = 0 ; i < l ; i++)
  42. {
  43. int id = idx(s[i]);
  44. if (p->next[id] == NULL)     //没有这个单词
  45. return false;
  46. p = p->next[id];
  47. }
  48. if (p->word)
  49. return true;
  50. return false;       //如果有些单词只是 "路过" 也不算
  51. }
  52. int main()
  53. {
  54. ant = 1;
  55. tree[0].clear();
  56. char str[50011][30];
  57. int num = 0;
  58. while (~scanf ("%s",str[num++]))
  59. insert(str[num-1]);
  60. for (int i = 0 ; i < num ; i++)      //从第一个单词开始拆
  61. {
  62. int l = strlen(str[i]);
  63. for (int j = 1 ; j < l ; j++)
  64. {
  65. char a[30];
  66. strncpy(a,str[i],j);
  67. a[j] = '\0';        //strncpy函数不添加'\0'
  68. char b[30];
  69. strcpy(b,str[i]+j);
  70. if (find(a) && find(b))
  71. {
  72. printf ("%s\n",str[i]);
  73. break;      //输出完此轮不用再搜了
  74. }
  75. }
  76. }
  77. return 0;
  78. }

字典树 静态建树与动态建树相关推荐

  1. 【leetcode】JS 字典树 建树 查找键 查找键前缀【模板】

    var findWords = function(grid, words) {// 存放最终结果集let res = []// 字典树节点class TrieNode {constructor(){t ...

  2. 动态建树之——查字典

    题目:poj2503 题意:给几个单词的意思,再给几个单词,查字典~ 解答:字典树咯(注意节点定义,每个节点定义一个字符数组) 注意:空行停止!!! #include<iostream> ...

  3. 3764树上的异或值(自己研究的静态字典树)

    题意:       给一颗树,最多10W个点,然后每条边上都有一个权值,任意两点的权值是他们经过的边的异或值,问最大的权值是多少?(任意两点中最大的) 思路:       首先突破口是要想到a^b=c ...

  4. 树状数组O(n)建树

    题目来源 以这道题为例子 首先我们知道树状数组是这样的: 图中的C数组就是我们的树状数组: 暴力建树 首先我们可以通过单点修改的方式,暴力建树,但是这种是O(nlogn)O(nlogn)O(nlogn ...

  5. 动态建树加深搜之——模仿手机九键输入法

    题目:poj1451 题意:给你一个词语出现次数的表,然后给你一个输入的数字串,每一步输出它最可能出现的单词.没有了就输出一个东西. 解答:建一个字典树,然后深度遍历这课树.每遍历一步都要记录下当前的 ...

  6. 字典树,01字典树,可持续化01字典树(总结+例题)

    目录 字典树 01字典树 字典树例题: power oj 2390: 查单词 HDU 1671 Phone List HDU 1004Let the Balloon Rise HDU 1075 Wha ...

  7. 【亡羊补牢】挑战数据结构与算法 第19期 LeetCode 212. 单词搜索 II(字典树,附上JS模板)

    仰望星空的人,不应该被嘲笑 题目描述 给定一个二维网格 board 和一个字典中的单词列表 words,找出所有同时在二维网格和字典中出现的单词. 单词必须按照字母顺序,通过相邻的单元格内的字母构成, ...

  8. Tre树(字典树)数据结构详解(图解)及模板

    了解这个数据结构之前我们需要了解它能被用来做什么 字典树又称单词查找树,Tire树,是一种树形结构,是一种哈希树的变种.典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引 ...

  9. [ACM] hdu 1671 Phone List (字典树)

    [ACM] hdu 1671 Phone List (字典树) Phone List Problem Description Given a list of phone numbers, determ ...

最新文章

  1. python调用c++动态库 linux_linux中使用boost.python调用c++动态库的方法
  2. python生成条形图-Python处理JSON数据并生成条形图
  3. unicode编码转ascii编码
  4. JasperReports:棘手的部分
  5. access下如何配置两个vlan_不同vlan间的通信如何简单配置(三种方式) ?
  6. 大数据公司Palantir曾向法拉第未来投资2500万美元
  7. 【C++ Primer】第十三章 类继承
  8. Eclipse发布Web项目
  9. 浅谈企业信息化规划建设
  10. 生成大量随机数(c语言)
  11. SQL Server存储过程文本加密与解密过程详解 2019版可用
  12. 矩阵求导术(二)——矩阵对矩阵的求导
  13. vue-学生信息管理系统
  14. k8s 集群全部更换机器 IP
  15. Servlet 使用getRequestDispatcher进行请求转发页面未跳转 后台也未报错的问题的解决方法
  16. 时代潮流-云原生数据库的崛起
  17. tp5微信公众号发送模板消息
  18. FITC cy3/cy5荧光标记达卡巴嗪/托瑞米芬/盐酸阿霉素/替莫唑胺等药物 FITC-DTIC
  19. 几种最小二乘法及python代码:ELS、TLS、RLS
  20. 打了平安的新股,可惜一签没中

热门文章

  1. 如何把视频mp4转换mp3音乐
  2. 搜索推荐算法系列文章整理
  3. fluxbox_使用Fluxbox Linux桌面作为窗口管理器
  4. 代码签名证书_代码签名
  5. 基于SSH的羽毛球场地预定系统毕业设计-运动场地预定系统 源码 java-体育馆预定场地管理系统-场馆预约系统
  6. springboot毕设项目蔬菜种植水肥一体化管理系统70ro1(java+VUE+Mybatis+Maven+Mysql)
  7. 4000元以内的台式计算机,4000元左右台式电脑推荐最好联想的
  8. R语言对大文件excel按行分解。
  9. 互联网晚报 | 10月7日 星期四 | 小米中东欧5G手机市占率排名第一;威马汽车将再获5亿美元融资;诺基亚首款平板T20发布...
  10. 软件定义存储(SDS)之入门