150 likes | 279 Views
ACM 程序设计. 集训队讲座. 字典树 ( Trie ). 导引问题 ( HDOJ- 1251 ). Ignatius 最近遇到一个难题 , 老师交给他很多单词 ( 只有小写字母组成 , 不会有重复的单词出现 ), 现在老师要他统计出以某个字符串为前缀的单词数量 ( 单词本身也是自己的前缀 ). 初步分析 ( Brute-force ). 假设单词表容量为 M ,需要统计的前缀数量为 N ,单词的平均长度为 L ,则常规算法的时间复杂度是?. Question: 如果单词表容量很大 -> 查找效率 ? -> 低 更有效率的方法:字典树. 什么是字典树?.
E N D
集训队讲座 字典树(Trie)
导引问题(HDOJ-1251) Ignatius最近遇到一个难题,老师交给他很多单词(只有小写字母组成,不会有重复的单词出现),现在老师要他统计出以某个字符串为前缀的单词数量(单词本身也是自己的前缀).
初步分析(Brute-force) 假设单词表容量为M,需要统计的前缀数量为N,单词的平均长度为L,则常规算法的时间复杂度是? Question: 如果单词表容量很大->查找效率? ->低 更有效率的方法:字典树
什么是字典树? 字典树:又称为Trie,是一种用于快速检索的多叉树结构。Trie把要查找的关键词看作一个字符序列,并根据构成关键词字符的先后顺序构造用于检索的树结构;一棵m度的Trie树或者为空,或者由m棵m度的Trie树构成。 特别地:和二叉查找树不同,在Trie树中,每个结点上并非存储一个元素。
Trie的图示 特点: • 利用串的公共前缀->节约内存 • 根结点不包含任何字母 • 其余结点仅包含一个字母(非元素) • 每个结点的子节点包含字母不同
Trie的查找(最主要的操作) (1)在trie树上进行检索总是始于根结点。 (2)取得要查找关键词的第一个字母,并根据该字母选择对应的子树并转到该子树继续进行检索。 (3)在(5)在某个结点处,关相应的子树上,取得要查找关键词的第二个字母,并进一步选择对应的子树进行检索。 (4) ... 键词的所有字母已被取出,则读取附在该结点上的信息,即完成查找。
Trie的数据结构定义 • struct dictree • { • dictree *child[26]; • int n; //根据需要变化 • }; • dictree *root;
查找效率分析 • 在trie树中查找一个关键字的时间和树中包含的结点数无关,而取决于组成关键字的字符数。(对比:二叉查找树的查找时间和树中的结点数有关O(log2n)。) • 如果要查找的关键字可以分解成字符序列且不是很长,利用trie树查找速度优于二叉查找树。 • 若关键字长度最大是5,则利用trie树,利用5次比较可以从265=11881376个可能的关键字中检索出指定的关键字。而利用二叉查找树至少要进行log2265=23.5次比较。
示例—(HDOJ-1075) What Are You Talking About 题目描述:Ignatius is so lucky that he met a Martian yesterday. But he didn't know the language the Martians use. The Martian gives him a history book of Mars and a dictionary when it leaves. Now Ignatius want to translate the history book into English. Can you help him?
样本数据(HDOJ-1075) Sample Output hello, i'm from mars. i like earth! Sample Input START from fiwo hello difh mars riwosf earth fnnvk like fiiwj END START difh, i'm fiwo riwosf. i fiiwj fnnvk! END • Input Description: All the words are in the lowercase, and each word will contain at most 10 characters, and each line will contain at most 3000 characters.
题目分析(HDOJ-1075) • 特点?数据量大 • 主要任务?查找单词 • 解决方法?字典树 • 字典树结构(除指针)?单词信息(英文) • 额外提醒?字符串操作的熟练应用 • 其他问题?NO~
相关练习 • HDOJ-1075 WhatAre You Talking About • HDOJ-1251 统计难题 • HDOJ-1298 T9 • HDOJ-1800 Flying to the Mars • ZOJ-1109 Language of FatMouse
附:参考源码(HDOJ-1251) • int find(char *source) • { • int i,len; • struct dictree *current; • len=strlen(source); • if(len==0) return 0; • current=root; • for(i=0;i<len;i++) • { • if(current->child[source[i]-'a']!=0) • current=current->child[source[i]-'a']; • else return 0; • } • return current->n; • } • int main() • { • char temp[11]; • int i,j; • root=(struct dictree *)malloc(sizeof(struct dictree)); • for(i=0;i<26;i++) • root->child[i]=0; • root->n=2; • while(gets(temp),strcmp(temp,"")!=0) • insert(temp); • while(scanf("%s",temp)!=EOF) • { • i=find(temp); • printf("%d\n",i); • } • } • #include "stdio.h" • #include "string.h" • #include "stdlib.h" • struct dictree • { • struct dictree *child[26]; • int n; • }; • struct dictree *root; • void insert (char *source) • { • int len,i,j; • struct dictree *current,*newnode; • len=strlen(source); • if(len==0) return; • current=root; • for(i=0;i<len;i++) • { • if(current->child[source[i]-'a']!=0) • { • current=current->child[source[i]-'a']; • current->n=current->n+1; • } • else • { • newnode=(struct dictree *)malloc(sizeof(struct dictree)); • for(j=0;j<26;j++) • newnode->child[j]=0; • current->child[source[i]-'a']=newnode; • current=newnode; • current->n=1; • } • } • }
Welcome to HDOJ Thank You ~