练习:Trie树(公共前缀)
2016-01-27 14:52
134 查看
Trie树,又称字典树,单词查找树或者前缀树,是一种用于快速检索的多叉树结构。
它的精髓在于利用字符串的公共前缀来节约存储空间。从根节点到某一个节点,路径上经过的字符连接起来,为该节点对应的字符串。(举例如下图)
Trie树的应用很多,主要是以下几个方面:
(1)正如“前缀树”的定义一样,Trie树可以方便地检索字符串,查找字符串的公共前缀等。更为重要的是,建立Trie树的过程,其实也是查询的过程。
(2)排序。只要先序遍历整棵树,输出相应的字符串便是按字典序排序的结果。
(3)其他数据结构和算法的基础:如AC自动机、后缀树等。
下面通过hihoCoder上的一个例子,编程练习。
给定一个含有n(n≤100000)个单词的字典,每个单词由不超过10个的小写英文字母组成(可能存在相同的单词,此时应将其视作不同的单词)。
接下来有m(m≤100000)次询问,每次询问要求回答字典中以给定字符串为前缀的单词的个数
【样例输入】
5
babaab
babbbaaaa
abba
aaaaabaa
babaababb
5
babb
baabaaa
bab
bb
bbabbaab
【样例输出】
1
0
3
0
0
【我的程序】
这是Trie树的经典练习,在程序中,我采用孩子兄弟表示法来储存这棵Trie树。
它的精髓在于利用字符串的公共前缀来节约存储空间。从根节点到某一个节点,路径上经过的字符连接起来,为该节点对应的字符串。(举例如下图)
Trie树的应用很多,主要是以下几个方面:
(1)正如“前缀树”的定义一样,Trie树可以方便地检索字符串,查找字符串的公共前缀等。更为重要的是,建立Trie树的过程,其实也是查询的过程。
(2)排序。只要先序遍历整棵树,输出相应的字符串便是按字典序排序的结果。
(3)其他数据结构和算法的基础:如AC自动机、后缀树等。
下面通过hihoCoder上的一个例子,编程练习。
给定一个含有n(n≤100000)个单词的字典,每个单词由不超过10个的小写英文字母组成(可能存在相同的单词,此时应将其视作不同的单词)。
接下来有m(m≤100000)次询问,每次询问要求回答字典中以给定字符串为前缀的单词的个数
【样例输入】
5
babaab
babbbaaaa
abba
aaaaabaa
babaababb
5
babb
baabaaa
bab
bb
bbabbaab
【样例输出】
1
0
3
0
0
【我的程序】
这是Trie树的经典练习,在程序中,我采用孩子兄弟表示法来储存这棵Trie树。
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct triNode //孩子兄弟表示法 { char c; long int num; struct triNode* fChild; struct triNode* rCousin; }* triTree; triTree newTree(char c) //新建一棵子树 { triTree p=(triTree) malloc(sizeof(struct triNode)); p->c=c; p->num=1; p->fChild=NULL; p->rCousin=NULL; return p; } void dictionary(triTree t) //建立字典树 { long int n,i; char s[11]; scanf("%ld",&n); for (i=0;i<n;i++) { scanf("%s",s); long int len=strlen(s),j,k; triTree x=t,y; for (j=0;j<len;j++) { y=x->fChild; if (y==NULL) //当前结点没有子树,则将剩余字符串全部插入 { for (k=j;k<len;k++) { x->fChild=newTree(s[k]); x=x->fChild; } break; } int flag=0; while (y!=NULL) { if (y->c==s[j]) {flag=1;break;} x=y; y=y->rCousin; } if (flag==0) //未找到当前字符,则增加一棵子树作为右兄弟 { x->rCousin=newTree(s[j]); x=x->rCousin; for (k=j+1;k<len;k++) { x->fChild=newTree(s[k]); x=x->fChild; } break; } else //找到当前字符,将经过当前结点的字符串个数加1 { x=y; x->num++; } } } } void response(triTree t) //查询过程和建树过程同理,且更简单 { long int m,i; scanf("%ld",&m); for (i=0;i<m;i++) { char s[30]; scanf("%s",s); long int len=strlen(s),j; triTree y=t; for (j=0;j<len;j++) { y=y->fChild; if (y==NULL) {printf("0\n");break;} while (y!=NULL) { if (y->c==s[j]) break; y=y->rCousin; } if (y==NULL) {printf("0\n");break;} } if (j==len) printf("%ld\n",y->num); } } int main() { triTree t=newTree('0'); dictionary(t); response(t); return 0; }
相关文章推荐
- 百度云限速破解
- 使用ORACLE开窗函数over()进行重复数据的删除【自用】
- saltstack远程操作WINDOWS的POWERSHELL脚本
- velocity常用语句速查表
- 利用rem解决移动端响应适配问题
- openstack(liberty): devstack中的iniset/iniget函数分析
- postgresql 聚合的暗坑
- Java - String, StringBuffer and StringBuilder
- CSS3+Sprite实现僵尸行走动画特效源码
- 链表---Reverse Linked List
- Drupal常用开发工具(二)——Drupal for Firebug
- 卸载Framework 2.0
- 你不是迷茫,你是自制力不强
- 什么是卡盟
- 引用iscroll的一个封装方法
- CI框架 -- 密码哈希
- java正则表达式取括号里面的内容
- 【EF 4】ORM框架及其流行产品之一EF介绍
- 基于iSCSI下的openfiler2.99下使逻辑卷最大化(命令行方式)
- 京东面试记录