http://acm.hdu.edu.cn/showproblem.php?pid=1251
初学字典树
词典树,又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来节约存储空间,最大限度地减少无谓的字符串比较,查询效率比哈希表高。
1、性质 它有3个基本性质: 根节点不包含字符,除根节点外每一个节点都只包含一个字符。 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。 每个节点的所有子节点包含的字符都不相同。
2、基本操作 其基本操作有:查找 插入和删除,当然删除操作比较少见.
3、实现方法 搜索字典项目的方法为(1) 从根结点开始一次搜索; (2) 取得要查找关键词的第一个字母,并根据该字母选择对应的子树并转到该子树继续进行检索; (3) 在相应的子树上,取得要查找关键词的第二个字母,并进一步选择对应的子树进行检索。 (4) 迭代过程…… (5) 在某个结点处,关键词的所有字母已被取出,则读取附在该结点上的信息,即完成查找。 其他操作类似处理
4、应用 串的快速检索 给出N个单词组成的熟词表,以及一篇全用小写英文书写的文章,请你按最早出现的顺序写出所有不在熟词表中的生词。 在这道题中,我们可以用数组枚举,用哈希,用字典树,先把熟词建一棵树,然后读入文章进行比较,这种方法效率是比较高的。 “串”排序 给定N个互不相同的仅由一个单词构成的英文名,让你将他们按字典序从小到大输出 用字典树进行排序,采用数组的方式创建字典树,这棵树的每个结点的所有儿子很显然地按照其字母大小排序。对这棵树进行先序遍历即可。 最长公共前缀问题 对所有串建立字典树,对于两个串的最长公共前缀的长度即他们所在的结点的公共祖先个数,于是,问题就转化为最近公共祖先问题。
#include<stdio.h> #include<string.h> #include<stdlib.h> typedef struct node { struct node *child[26];//这是接下去的字母的指针 int n;//存储信息,可变。这里存的是以到此为止的字符串为前缀的单词量 }Trie; Trie *root; int build(char *str) { int len=strlen(str),i,j; Trie *s,*l; if(len==0)return 0; s=root; for(i=0;i<len;i++) { if(s->child[str[i]-'a']==NULL)//当接下去的的指针为空时,新申请一个节点出来,存储信息, { l=(Trie *)malloc(sizeof(Trie)); l->n=1;//初始化是1 for(j=0;j<26;j++) l->child[j]=NULL; s->child[str[i]-'a']=l;//往下走 s=l; } else { s=s->child[str[i]-'a'];//这里因为在根结点处为存储东西,所以要先找到下个结点,然后再进行信息的更新 s->n++; } } } int find(char str[]) { int i,len=strlen(str); Trie *s=root; for(i=0;i<len;i++) { if(s->child[str[i]-'a'])//在有连接的情况下才往下走 s=s->child[str[i]-'a']; else return 0;//单词没找到就返回0,否则返回答案 } return s->n;// } int main() { int i; char s[20]; root=(Trie *)malloc(sizeof(Trie)); for(i=0;i<26;i++) root->child[i]=NULL; root->n=0;//初始化为0; while(gets(s),strcmp(s,"")) build(s); while(scanf("%s",s)!=EOF) printf("%d ",find(s)); return 0; }