字典树 静态建树与动态建树
http://blog.csdn.net/wyg1997/article/details/52121597
其实动态建树和静态建树都一样,只是动态建树省空间费时间,静态建树省时间费空间。
那么如果碰上数据很大的题的时候,还是选择静态建树吧,毕竟内存没有那么容易超。
那下面先说动态建树吧:
变量:
- struct Trie
- {
- Trie *next[10];
- int v;
- void init()
- {
- v = 0;
- for (int i = 0 ; i <= 9 ; i++)
- next[i] = NULL;
- }
- };
- Trie *root;
next[] 指针数组指向下一个节点。数组大小根据题目改变,例如,题目要求只有小写字母,那么开26就行了;如果包括大写,那么开52,如果还有数字,那就是62(一般包括数字的话,个人感觉树的规模不会建的太大,要不就出事了)。
变量v的含义非常灵活,可以表示当前字母被共享使用了多少次,也可以变成bool型表示一个单词的结束。这个要就题论题,不能太拘泥模板。
*root 表示指向根节点的指针,每次查询要先从根节点(不包括任何字母)开始。
初始化:
- root = (Trie *)malloc(sizeof(Trie));
- root->init();
第一行代码给 *root 指向的结构体开辟空间,第二行初始化root。
插入字符串:
- void insert(char *s) //字符串
- {
- int l = strlen(s);
- Trie *p = root , *q;
- for (int i = 0 ; i < l ; i++)
- {
- int id = idx(s[i]);
- if (p->next[id] == NULL)
- {
- q = (Trie *)malloc(sizeof(Trie)); //开新指针
- q->init();
- p->next[id] = q;
- }
- p = p->next[id];
- p->v++;
- }
- }
思路大概就是,从字符串中依次取字符,如果树的枝叶有这个字符,那么就顺着这个枝叶对下一个字符进行操作,如果不存在,就再开一个叶子存这个字母。
注意:我这里的v的意思是这个位置的字母被多少字符串共享,其他使用要就题来改变。
查找操作:
- bool find(char *s)
- {
- int l = strlen(s);
- Trie *p = &tree[0];
- for (int i = 0 ; i < l ; i++)
- {
- int id = idx(s[i]);
- if (p->next[id] == NULL) //没有这个单词
- return false;
- p = p->next[id];
- }
- if (p->word)
- return true;
- return false; //如果有些单词只是 "路过" 也不算
- }
PS:这时候的word变量代替了之前的变量v,表示这个位置是否形成了单词。
这个函数的用法是查询一个单词是否出现过。如果插入操作看懂了,这个应该不难,就不细讲了。
查找最小前缀并输出:
- void min_permix(char s[][22],int x) //查询最小前缀
- {
- printf ("%s ",s[x]);
- int l = strlen(s[x]);
- Trie *p = root;
- for (int i = 0 ; i < l ; i++)
- {
- printf ("%c",s[x][i]);
- int id = idx(s[x][i]);
- p = p->next[id];
- if (p->v == 1) //如果字母单独出现说明已经出现最小前缀了,结束
- break;
- }
- printf ("\n");
- }
这个也应该不难理解了。
释放内存:(有些题需要把结构体开辟的内存释放掉,要不会MLE)
- void del(Trie *root) //不释放内存的话会MLE
- {
- for (int i = 0 ; i < 10 ; i++)
- {
- if (root->next[i] != NULL)
- del(root->next[i]);
- }
- free(root);
- }
使用free函数+dfs释放内存。
然后说一下静态储存:
- struct Trie
- {
- Trie *next[10];
- int v;
- void init()
- {
- v = 0;
- for (int i = 0 ; i <= 9 ; i++)
- next[i] = NULL;
- }
- }tree[1<<16];
- int ant;
这个时候要把tree开的足够大,把你这棵树可能出现的最大枝叶树全部包括。
ant这个变量是动态的,不断往后开新的结构体来储存枝叶。(这一个不懂可以看一下下面的操作)(使用前记得初始化为1,而把tree[ 0 ] 作为根节点)
插入操作:
- void insert(char *s)
- {
- int l = strlen(s);
- Trie *p = &tree[0], *q; //tree[0]为根节点
- for (int i = 0 ; i < l ; i++)
- {
- int id = idx(s[i]);
- if (p->next[id] == NULL)
- {
- q = &tree[ant++];
- p->next[id] = q;
- }
- p = p->next[id];
- }
- p->v = -1; //这个-1表示一个字符串已经结束
- }
然后这个插入操作就不难理解了,其他操作类似动态的字典树,就不再一一码了。
然后贴一个大代码:
动态:(查找最小前缀)
- #include <cstdio>
- #include <cstring>
- #include <algorithm>
- using namespace std;
- #define CLR(a,b) memset(a,b,sizeof(a))
- #define INF 0x3f3f3f3f
- struct Trie
- {
- Trie *next[26];
- int v;
- void init()
- {
- v = 0;
- for (int i = 0 ; i < 26 ; i++)
- next[i] = NULL;
- }
- };
- Trie *root;
- int idx(char c)
- {
- return c - 'a';
- }
- void insert(char s[][22],int x)
- {
- int l = strlen(s[x]);
- Trie *p = root , *q;
- for (int i = 0 ; i < l ; i++)
- {
- int id = idx(s[x][i]);
- if (p->next[id] == NULL)
- {
- q = (Trie *)malloc(sizeof(Trie)); //开新指针
- q->init();
- p->next[id] = q;
- }
- p = p->next[id];
- p->v++;
- }
- }
- void min_permix(char s[][22],int x) //查询最小前缀
- {
- printf ("%s ",s[x]);
- int l = strlen(s[x]);
- Trie *p = root;
- for (int i = 0 ; i < l ; i++)
- {
- printf ("%c",s[x][i]);
- int id = idx(s[x][i]);
- p = p->next[id];
- if (p->v == 1) //如果字母单独出现说明已经出现最小前缀了,结束
- break;
- }
- printf ("\n");
- }
- int main()
- {
- char s[1011][22];
- int ant = 0;
- root = (Trie *)malloc(sizeof(Trie));
- root->init();
- while (~scanf ("%s",s[ant++]))
- insert(s,ant-1);
- for (int i = 0 ; i < ant ; i++)
- min_permix(s , i);
- return 0;
- }
静态:(查找某个字符串是否可以由已知的两个字符串拼接而成)
- #include <cstdio>
- #include <cstring>
- #include <algorithm>
- using namespace std;
- #define CLR(a,b) memset(a,b,sizeof(a))
- #define INF 0x3f3f3f3f
- #define idx(x) (x-'a')
- struct Trie
- {
- Trie *next[26];
- bool word;
- void clear()
- {
- for (int i = 0 ; i < 26 ; i++)
- next[i] = NULL;
- word = false;
- }
- }tree[100000];
- int ant;
- void insert(char *s)
- {
- int l = strlen(s);
- Trie *p = &tree[0] , *q;
- for (int i = 0 ; i < l ; i++)
- {
- int id = idx(s[i]);
- if (p->next[id] == NULL)
- {
- q = &tree[ant++];
- q->clear();
- p->next[id] = q;
- }
- p = p->next[id];
- }
- p->word = true;
- }
- bool find(char *s)
- {
- int l = strlen(s);
- Trie *p = &tree[0];
- for (int i = 0 ; i < l ; i++)
- {
- int id = idx(s[i]);
- if (p->next[id] == NULL) //没有这个单词
- return false;
- p = p->next[id];
- }
- if (p->word)
- return true;
- return false; //如果有些单词只是 "路过" 也不算
- }
- int main()
- {
- ant = 1;
- tree[0].clear();
- char str[50011][30];
- int num = 0;
- while (~scanf ("%s",str[num++]))
- insert(str[num-1]);
- for (int i = 0 ; i < num ; i++) //从第一个单词开始拆
- {
- int l = strlen(str[i]);
- for (int j = 1 ; j < l ; j++)
- {
- char a[30];
- strncpy(a,str[i],j);
- a[j] = '\0'; //strncpy函数不添加'\0'
- char b[30];
- strcpy(b,str[i]+j);
- if (find(a) && find(b))
- {
- printf ("%s\n",str[i]);
- break; //输出完此轮不用再搜了
- }
- }
- }
- return 0;
- }
字典树 静态建树与动态建树相关推荐
- 【leetcode】JS 字典树 建树 查找键 查找键前缀【模板】
var findWords = function(grid, words) {// 存放最终结果集let res = []// 字典树节点class TrieNode {constructor(){t ...
- 动态建树之——查字典
题目:poj2503 题意:给几个单词的意思,再给几个单词,查字典~ 解答:字典树咯(注意节点定义,每个节点定义一个字符数组) 注意:空行停止!!! #include<iostream> ...
- 3764树上的异或值(自己研究的静态字典树)
题意: 给一颗树,最多10W个点,然后每条边上都有一个权值,任意两点的权值是他们经过的边的异或值,问最大的权值是多少?(任意两点中最大的) 思路: 首先突破口是要想到a^b=c ...
- 树状数组O(n)建树
题目来源 以这道题为例子 首先我们知道树状数组是这样的: 图中的C数组就是我们的树状数组: 暴力建树 首先我们可以通过单点修改的方式,暴力建树,但是这种是O(nlogn)O(nlogn)O(nlogn ...
- 动态建树加深搜之——模仿手机九键输入法
题目:poj1451 题意:给你一个词语出现次数的表,然后给你一个输入的数字串,每一步输出它最可能出现的单词.没有了就输出一个东西. 解答:建一个字典树,然后深度遍历这课树.每遍历一步都要记录下当前的 ...
- 字典树,01字典树,可持续化01字典树(总结+例题)
目录 字典树 01字典树 字典树例题: power oj 2390: 查单词 HDU 1671 Phone List HDU 1004Let the Balloon Rise HDU 1075 Wha ...
- 【亡羊补牢】挑战数据结构与算法 第19期 LeetCode 212. 单词搜索 II(字典树,附上JS模板)
仰望星空的人,不应该被嘲笑 题目描述 给定一个二维网格 board 和一个字典中的单词列表 words,找出所有同时在二维网格和字典中出现的单词. 单词必须按照字母顺序,通过相邻的单元格内的字母构成, ...
- Tre树(字典树)数据结构详解(图解)及模板
了解这个数据结构之前我们需要了解它能被用来做什么 字典树又称单词查找树,Tire树,是一种树形结构,是一种哈希树的变种.典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引 ...
- [ACM] hdu 1671 Phone List (字典树)
[ACM] hdu 1671 Phone List (字典树) Phone List Problem Description Given a list of phone numbers, determ ...
最新文章
- python调用c++动态库 linux_linux中使用boost.python调用c++动态库的方法
- python生成条形图-Python处理JSON数据并生成条形图
- unicode编码转ascii编码
- JasperReports:棘手的部分
- access下如何配置两个vlan_不同vlan间的通信如何简单配置(三种方式) ?
- 大数据公司Palantir曾向法拉第未来投资2500万美元
- 【C++ Primer】第十三章 类继承
- Eclipse发布Web项目
- 浅谈企业信息化规划建设
- 生成大量随机数(c语言)
- SQL Server存储过程文本加密与解密过程详解 2019版可用
- 矩阵求导术(二)——矩阵对矩阵的求导
- vue-学生信息管理系统
- k8s 集群全部更换机器 IP
- Servlet 使用getRequestDispatcher进行请求转发页面未跳转 后台也未报错的问题的解决方法
- 时代潮流-云原生数据库的崛起
- tp5微信公众号发送模板消息
- FITC cy3/cy5荧光标记达卡巴嗪/托瑞米芬/盐酸阿霉素/替莫唑胺等药物 FITC-DTIC
- 几种最小二乘法及python代码:ELS、TLS、RLS
- 打了平安的新股,可惜一签没中
热门文章
- 如何把视频mp4转换mp3音乐
- 搜索推荐算法系列文章整理
- fluxbox_使用Fluxbox Linux桌面作为窗口管理器
- 代码签名证书_代码签名
- 基于SSH的羽毛球场地预定系统毕业设计-运动场地预定系统 源码 java-体育馆预定场地管理系统-场馆预约系统
- springboot毕设项目蔬菜种植水肥一体化管理系统70ro1(java+VUE+Mybatis+Maven+Mysql)
- 4000元以内的台式计算机,4000元左右台式电脑推荐最好联想的
- R语言对大文件excel按行分解。
- 互联网晚报 | 10月7日 星期四 | 小米中东欧5G手机市占率排名第一;威马汽车将再获5亿美元融资;诺基亚首款平板T20发布...
- 软件定义存储(SDS)之入门