字典树学习小结
来源:互联网 发布:linux vsftpd 启动 编辑:程序博客网 时间:2024/05/20 19:33
写了几道字典树的基础题了,现在写一个总结吧。
其实动态建树和静态建树都一样,只是动态建树省空间费时间,静态建树省时间费空间。
那么如果碰上数据很大的题的时候,还是选择静态建树吧,毕竟内存没有那么容易超。
那下面先说动态建树吧:
变量:
struct Trie{Trie *next[10];int v;void init(){v = 0;for (int i = 0 ; i <= 9 ; i++)next[i] = NULL;}};Trie *root;
变量v的含义非常灵活,可以表示当前字母被共享使用了多少次,也可以变成bool型表示一个单词的结束。这个要就题论题,不能太拘泥模板。
*root 表示指向根节点的指针,每次查询要先从根节点(不包括任何字母)开始。
初始化:
root = (Trie *)malloc(sizeof(Trie));root->init();
插入字符串:
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 0x3f3f3f3fstruct 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;}
有错误欢迎留言指出。
如果感觉写的不错,转载请表明出处链接哦~
0 0
- 字典树学习小结
- Trie(字典树)学习小结1
- 字典树小结
- 字典树小结
- 字典树小结
- 字典树小结
- 01字典树 小结
- 字典树入门小结
- 字典树小结
- 字典树小结
- 字典树学习
- 字典树学习材料
- 字典树学习
- 学习 字典树
- 字典树学习
- 字典树学习
- 字典树学习总结
- 字典树 学习笔记
- Mysql的数据库类型
- (六)、ZooKeeper自动重连
- 【JQuery,前端】Jquery.Datatables 基本创建方法
- .net 概述
- 三分钟配好MySQL主从复制 - 问题集锦
- 字典树学习小结
- 实时SLAM的未来及深度学习与SLAM对比
- 安装ArcGIS 10.2遇到问题
- 虚函数的实现机制
- 【JQuery,前端】jquery datatables 学习笔记
- LoadRunner关联获取web内容,并设置为变量
- eclipse检测不到手机或模拟器
- linux mprotect 修改用户态内存的方法
- spark启动中遇到的问题