单词查找树

合集下载

Trie树高效存储和检索字符串集合

Trie树高效存储和检索字符串集合

Trie树高效存储和检索字符串集合Trie树,也称为字典树或者前缀树,是一种非常高效的数据结构,用于存储和检索字符串集合。

它通过利用字符串的公共前缀来减少存储空间,并且可以在O(k)的时间复杂度下查找字符串,其中k是字符串的长度。

本文将介绍Trie树的原理和应用,并展示它在存储和检索字符串集合方面的优势。

一、Trie树的原理Trie树的基本思想是通过将每个字符串拆分为字符节点,并将字符节点以树形结构连接起来,从而形成一个维护字符串集合的数据结构。

它的根节点不包含任何字符,每个子节点代表一个字符,并通过连接方式表示字符串的各个字符之间的关系。

在Trie树中,每个节点都可以包含一个或多个子节点,每个节点的子节点表示在该位置上可能存在的下一个字符。

通过遍历从根节点到叶子节点的路径,我们可以得到一个完整的字符串。

这种结构使得Trie树特别适用于存储大量的字符串,并且可以高效地检索它们。

二、Trie树的构建构建Trie树的过程需要遍历每个字符串,并将它们的字符按照顺序插入到树中。

首先创建一个根节点,然后遍历每个字符串,对于每个字符,我们检查它是否已经是当前节点的子节点。

如果是,则将当前节点更新为该子节点,并继续遍历下一个字符;如果不是,则创建一个新节点,并将其作为当前节点的子节点,然后更新当前节点为新创建的节点,并继续遍历下一个字符。

重复这个过程,直到遍历完所有的字符串。

三、Trie树的应用1. 单词查找由于Trie树可以高效地查找字符串,因此它在单词查找中得到了广泛的应用。

例如,在文本编辑器中,我们可以使用Trie树来实现自动完成功能,根据用户已输入的前缀快速找到匹配的单词。

另外,Trie 树还可以用于拼写检查和单词纠错等应用场景。

2. IP地址查找在网络领域,Trie树也被广泛应用于IP地址查找。

通过将IP地址拆分为多个部分,并构建相应的Trie树,我们可以快速检索到给定IP 地址所对应的地理位置或者网络信息。

数据结构专业英语词汇汇总

数据结构专业英语词汇汇总

数据结构专业英语词汇汇总
- Data structure: 数据结构
- Array: 数组
- Linked list: 链表
- Stack: 栈
- Queue: 队列
- Binary tree: 二叉树
- AVL tree: AVL树 (一种自平衡二叉查找树)
- Red-black tree: 红黑树 (一种自平衡二叉查找树)
- Hash table: 哈希表
- Graph: 图
- Vertex: 顶点
- Edge: 边
- Adjacency list: 邻接表 (一种表示图的数据结构)
- Adjacency matrix: 邻接矩阵 (一种表示图的数据结构) - Heap: 堆
- Binary heap: 二叉堆 (一种特殊的堆数据结构)
- Priority queue: 优先队列 (用堆实现的一种队列)
- Trie: 字典树 (一种用于快速检索的树形数据结构)
- Big O notation: 大O符号 (一种表示算法时间复杂度的记号) - Sorting algorithm: 排序算法
- Searching algorithm: 算法
- Abstract data type (ADT): 抽象数据类型
- Hashing: 哈希函数的计算过程
- Collision: 哈希冲突 (发生在两个不同的键值被映射到相同的哈希桶时)。

树和二叉树的基本知识

树和二叉树的基本知识

树和二叉树的基本知识Jsoi2006春季函授 B层次讲义(3)常州市第一中学林厚从 1/53树和二叉树的基本知识树是一种非线性的数据结构,用它能很好地描述有分支和层次特性的数据集合。

树型结构在现实世界中广泛存在,如把一个家族看作为一棵树,树中的结点为家族成员的姓名及相关信息,树中的关系为父子关系,即父亲是儿子的前驱,儿子是父亲的后继;把一个国家或一个地区的各级行政区划分看作为一棵树,树中的结点为行政区的名称及相关信息,树中的关系为上下级关系,如一个城市包含有若干个区,每个区又包含有若干个街道,每个街道又包含有若干个居委会;把一本书的结构看作是一棵树,树中的结点为书、章、节的名称及相关信息,树中的关系为包含关系。

树在计算机领域中也有广泛应用,如在编译系统中,用树表示源程序的语法结构;在数据库系统中,树型结构是数据库层次模型的基础,也是各种索引和目录的主要组织形式。

在许多算法中,常用树型结构描述问题的求解过程、所有解的状态和求解的对策等。

在树型结构中,二叉树是最常用的结构,它的分支个数确定,又可以为空,具有良好的递归特性,特别适宜于程序设计,因此我们常常将一般树型结构转换成二叉树进行处理。

第一节树一、树的定义一棵树(tree)是由n(n>0)个元素组成的有限集合,其中:1.每个元素称为结点(node);2.有一个特定的结点,称为根结点或树根(root);3.除根结点外,其余结点被分成m(m>=0)个互不相交的有限集合T0,T1,T2,……Tm-1,而每一个子集Ti又都是一棵树(称为原树的子树subtree)。

图1图1就是一棵典型的树结构。

从树的定义可以看出:1.树是递归定义的,这就决定了树的操作和应用大都是采用递归思想来解决;2.一棵树中至少有1个结点,这个结点就是根结点,如上图中的结点1;3.只有根结点没有前趋结点,其余每个结点都有唯一的一个前趋结点;4.所有结点都可以有0或多个后继结点;二、树的基本概念下面以图1为例给出树结构中的一些基本概念:1.一个结点的子树个数,称为这个结点的度(degree),如结点1的度为3,结点3的度为0。

计算机科学中的树

计算机科学中的树

·AVL树·红黑树·伸展树·树堆·节点大小平衡树·B+树·B*树·B x树·UB树·2-3树·2-3-4·(a,b)-树·Dancing tree ·H树·基数树·八叉树·k-d树·vp-树·R树·R*树·R+树·X ·线段树·希尔伯特R树·优先R树并且左右两个子树都是一棵平衡二叉树。

构造与调整方法平衡二叉树的常用算法有红黑树、AVL、Treap、伸展树等。

堆(二叉堆)---------------------------------------------------------------------------------------------------------------堆是一种完全二叉树,效率很高,常用的排序算法、Dijkstra算法、Prim算法等都要用堆(优先级队列)优化。

一般的二叉堆不能进行有效查找和堆之间的合并。

(插入,获得及删除最小值)可并堆可以在O(logN)时间内完成两个堆的合并操作的二叉堆。

如左偏堆,二项堆,斐波那契堆。

最优二叉树(哈夫曼树)-----------------------------------------------------------------------------------------------------------------给定n个权值作为n个叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman tree)。

字典树----------------------------------------------------------------------------------------------------------------又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。

信息学奥赛一本通ybtssoiercn8088数据结构第三章树

信息学奥赛一本通ybtssoiercn8088数据结构第三章树
2.从根结点到某一结点,路径上经过的字母依次连起来所构成的字母序列,称为该结点对应的单 词。单词列表中的每个单词,都是该单词查找树某个结点所对应的单词;
3.在满足上述条件下,该单词查找树的结点数最少。
4.例如图3-2左边的单词列表就对应于右边的单词查找树。注意,对一个确定的单词列表,请统计 对应的单词查找树的结点数(包含根结点)。
14
if(i!=j)for(k=1;k<=n;k++)
15
if(k!=i&&k!=j)
16
g[i][j]=min(g[i][j],g[i][k]+g[k][j]);
17
for(i=1;i<=n;i++){//穷举医院的n个点
18
t=0;
19
for(j=1;j<=n;j++)t+=a[j]*g[i][j];
第一节 二叉树
1336:【例3-1】找树根和孩子 【题目描述】
给定一棵树,输出树的根root,孩子最多的结点max以及他的孩子。
【输入】
第一行:n(结点个数≤100),m(边数≤200)。 以下m行:每行两个结点x和y,表示y是x的孩子(x,y≤1000)。
【输出】
第一行:树根:root; 第二行:孩子最多的结点max; 第三行:max的孩子(按编号由小到输出)。
while(a[i][j]==a[i-1][j]&&j<a[i-1].length())j++;
13
t+=a[i].length()-j;//j肯定小于a[i].length()
14
}
15
cout<<t+1;//包含根节点

树和二叉树作业

树和二叉树作业

树和二叉树作业(一)一、基础知识题1、已知一棵度为m的树中有n1个度为1的结点,n2个度为2的结点,……,n m个度为m的结点,问树中有多少个叶子结点?2、由四个结点a、b、c、d组成二叉树,共有多少种不同的结构?3、已知一棵具有n个结点的完全二叉树被顺序地存储于一维数组A中,试编写一个算法,打印出编号为i的结点的双亲和所有孩子。

4、写出对二叉树进行中序遍历的非递归算法。

5、已知一组元素为(46,25,78,62,12,37,70,29),画出按元素排列顺序输入生成的一棵二叉排序树。

6、已知一棵二叉排序树如下图所示,若从中依次删除72、12、49、28结点,试分别画出每删除一个结点后得到的二叉排序树。

7、有七个带权结点a、b、c、d、e、f、g,分别带权3、7、8、2、5、8、4,试以它们为叶子结点构造一棵哈夫曼树(请按照左子树根结点的权小于等于右子树根结点的权的次序构造)。

8、在一份电文中,共用到了五种字符:a、b、c、d、e,它们的出现频率依次为4、7、5、2、9,试画出对应的编码哈夫曼树(请按照左子树根结点的权小于等于右子树根结点的要的次序构造),求出每个字符的哈夫曼编码。

二、编程题1、二叉树的遍历问题【问题描述】输入一棵二叉树的先序和中序遍历序列,输出其后序遍历序列。

输入:输入文件为tree.in,共两行,第一行一个字符串,表示树的先序遍历;第二行一个字符串,表示树的中序遍历。

树的结点一律用小写字母表示。

输出:输出文件为tree.out,仅一行,表示树的后序遍历序列。

【样例输入】abdecdbeac【样例输出】debca2、假定一棵树采用标准形式存储,试写出以广义表形式输出树的算法。

3、假定树采用标准形式存储,试写出求其深度的算法。

4、FBI树(fbi.pas)【问题描述】我们可以把由“0”和“1”组成的字符串分为三类:全“0”串称为B串,全“1”串称为I串,既含“0”又含“1”的串则称为F串。

1337:【例3-2】单词查找树

1337:【例3-2】单词查找树

1337:【例3-2】单词查找树时间限制: 1000 ms 内存限制: 65536 KB提交数: 1732 通过数: 910【题⽬描述】在进⾏⽂法分析的时候,通常需要检测⼀个单词是否在我们的单词列表⾥。

为了提⾼查找和定位的速度,通常都画出与单词列表所对应的单词查找树,其特点如下:1.根结点不包含字母,除根结点外每⼀个结点都仅包含⼀个⼤写英⽂字母;2.从根结点到某⼀结点,路径上经过的字母依次连起来所构成的字母序列,称为该结点对应的单词。

单词列表中的每个单词,都是该单词查找树某个结点所对应的单词;3.在满⾜上述条件下,该单词查找树的结点数最少。

4.例如图3-2左边的单词列表就对应于右边的单词查找树。

注意,对⼀个确定的单词列表,请统计对应的单词查找树的结点数(包含根结点)。

【输⼊】为⼀个单词列表,每⼀⾏仅包含⼀个单词和⼀个换⾏/回车符。

每个单词仅由⼤写的英⽂字母组成,长度不超过63个字母。

⽂件总长度不超过32K,⾄少有⼀⾏数据。

【输出】仅包含⼀个整数,该整数为单词列表对应的单词查找树的结点数。

【输⼊样例】AANASPASASCASCIIBASBASIC【输出样例】13【来源】No算法分析⾸先要对建树的过程有⼀个了解。

对于当前被处理的单词和当前树:在根节点的⼦结点中找单词的第⼀位字母,若存在,则进位在该节点的⼦结点中寻找第⼆位…如此下去直到单词结束,即不需要在该树中添加节点;或单词的第n位不能被找到,即将单词的第n位及其后的字母依次加⼊单词查找树中去。

但是,本题只是问节点总数,且有32K⽂件,所以应该考虑能不能不通过建树就直接算出节点总数。

定义⼀个单词相对于另⼀个单词的差:设单词1的长度为L,且与单词2从第N位开始不⼀致,则说单词1相对于单词2的差为L-N+1;,这是描述单词相似程度的量。

可见,将⼀个单词加⼊单词树的时候,须加⼊的节点等于该单词树中已有单词的差的最⼩值。

单词的字典顺序排序后的序列则具有类似的特性,即在⼀个字典顺序序列中,第m个单词相对于第m-1个单词的差必定是它对于前m-1个单词的差中最⼩的。

字典树Trie树的应用场景有哪些

字典树Trie树的应用场景有哪些

字典树Trie树的应用场景有哪些字典树(Trie 树)的应用场景有哪些在计算机科学领域,数据结构和算法的选择对于解决各种问题至关重要。

字典树(Trie 树)作为一种高效的数据结构,在众多应用场景中发挥着重要作用。

首先,我们来了解一下什么是字典树。

字典树,又称前缀树,是一种用于快速检索和存储字符串的数据结构。

它的特点是利用字符串的公共前缀来节省存储空间和提高查询效率。

那么,字典树具体在哪些方面有出色的应用呢?在搜索引擎中,字典树被广泛用于快速匹配关键词。

当用户输入搜索词时,搜索引擎需要在海量的网页数据中迅速找到相关的内容。

通过构建字典树,可以将常见的词汇和短语预先存储起来。

这样,在搜索过程中,能够快速判断输入的关键词是否存在,并快速定位相关的网页信息,从而大大提高搜索的响应速度和准确性。

在文本自动完成功能中,字典树也大显身手。

比如我们在输入文字时,输入法常常能够智能地给出可能的后续词汇。

这背后就可能使用了字典树。

输入法软件将常见的词汇和短语构建成字典树,当用户输入部分字符时,通过在字典树中进行查找和匹配,迅速给出可能的完整词汇,为用户提供便捷的输入体验。

字典树在拼写检查工具中也有着不可或缺的地位。

当我们输入一段文本时,拼写检查工具需要快速判断每个单词是否正确。

通过将正确的单词构建成字典树,然后对输入的单词在树中进行查找,如果找不到匹配项,就可以提示可能存在拼写错误。

在 IP 路由查找中,字典树同样能发挥作用。

IP 地址通常具有一定的规律和前缀,通过将 IP 地址段和对应的路由信息构建成字典树,可以实现快速的路由查找和转发,提高网络通信的效率。

在数据压缩方面,字典树也有其独特的价值。

对于重复出现的字符串序列,可以使用字典树来进行编码压缩,减少存储空间的占用。

在生物信息学领域,字典树用于处理基因序列等大量的字符串数据。

例如,在对基因序列进行相似性比较和分类时,字典树能够快速找到相同的基因片段,从而加速研究进程。

Trie

Trie
void insert(Trie_node* root,char* word) { char char_code; while(*word!=0) { char_code=*word-'a'; if(root->branch[char_code]==NULL) root->branch[char_code]=new Trie_node; root=root->branch[char_code]; word++; } root->data=1; }
trie树的实现(检索)
int search(Trie_node* root,char* word) { char char_code; Trie_node *location = root; while( location!=NULL && *word!=0 ) { char_code = *word-'a'; location = location->branch[char_code]; word++; } if ( location != NULL && location->data != 0 ) { return 1; } else return 0;// 不合法的单词 }
Trie树
trie树
什么是trie树? ◇ trie树是一种用于快速检索的多叉树结构。 ◇ 和二叉查找树不同,在trie树中,每个结点上并非存 储一个元素。 ◇ trie树把要查找的关键词看作一个字符序列。并根据 构成关键词字符的先后顺序构造用于检索的树结构。 ◇在trie树上进行检索类似于查阅英语词典。 一棵m度的trie树或者为空,或者由m棵m度的trie树构 成。

字典树(Trie树)实现与应用

字典树(Trie树)实现与应用

字典树(Trie树)实现与应⽤⼀、概述 1、基本概念 字典树,⼜称为单词查找树,Tire数,是⼀种树形结构,它是⼀种哈希树的变种。

2、基本性质根节点不包含字符,除根节点外的每⼀个⼦节点都包含⼀个字符从根节点到某⼀节点。

路径上经过的字符连接起来,就是该节点对应的字符串每个节点的所有⼦节点包含的字符都不相同 3、应⽤场景 典型应⽤是⽤于统计,排序和保存⼤量的字符串(不仅限于字符串),经常被搜索引擎系统⽤于⽂本词频统计。

4、优点 利⽤字符串的公共前缀来减少查询时间,最⼤限度的减少⽆谓的字符串⽐较,查询效率⽐哈希树⾼。

⼆、构建过程 1、字典树节点定义class TrieNode // 字典树节点{private int num;// 有多少单词通过这个节点,即由根⾄该节点组成的字符串模式出现的次数private TrieNode[] son;// 所有的⼉⼦节点private boolean isEnd;// 是不是最后⼀个节点private char val;// 节点的值TrieNode(){num = 1;son = new TrieNode[SIZE];isEnd = false;}} 2、字典树构造函数Trie() // 初始化字典树{root = new TrieNode();} 3、建⽴字典树// 建⽴字典树public void insert(String str) // 在字典树中插⼊⼀个单词{if (str == null || str.length() == 0){return;}TrieNode node = root;char[] letters = str.toCharArray();//将⽬标单词转换为字符数组for (int i = 0, len = str.length(); i < len; i++){int pos = letters[i] - 'a';if (node.son[pos] == null) //如果当前节点的⼉⼦节点中没有该字符,则构建⼀个TrieNode并复值该字符{node.son[pos] = new TrieNode();node.son[pos].val = letters[i];}else//如果已经存在,则将由根⾄该⼉⼦节点组成的字符串模式出现的次数+1{node.son[pos].num++;}node = node.son[pos];}node.isEnd = true;} 4、在字典树中查找是否完全匹配⼀个指定的字符串// 在字典树中查找⼀个完全匹配的单词.public boolean has(String str){if(str==null||str.length()==0){return false;}TrieNode node=root;char[]letters=str.toCharArray();for(int i=0,len=str.length(); i<len; i++){int pos=letters[i]-'a';if(node.son[pos]!=null){node=node.son[pos];}else{return false;}}//⾛到这⼀步,表明可能完全匹配,也可能部分匹配,如果最后⼀个字符节点为末端节点,则是完全匹配,否则是部分匹配return node.isEnd;} 5、前序遍历字典树 // 前序遍历字典树.public void preTraverse(TrieNode node){if(node!=null){System.out.print(node.val+"-");for(TrieNode child:node.son){preTraverse(child);}}} 6、计算单词前缀的数量 // 计算单词前缀的数量public int countPrefix(String prefix){if(prefix==null||prefix.length()==0){return-1;}TrieNode node=root;char[]letters=prefix.toCharArray();for(int i=0,len=prefix.length(); i<len; i++){int pos=letters[i]-'a';if(node.son[pos]==null){return 0;}elsenode=node.son[pos];}}return node.num;} 完整代码:package com.xj.test;public class Trie{private int SIZE = 26;private TrieNode root;// 字典树的根class TrieNode // 字典树节点{private int num;// 有多少单词通过这个节点,即由根⾄该节点组成的字符串模式出现的次数private TrieNode[] son;// 所有的⼉⼦节点private boolean isEnd;// 是不是最后⼀个节点private char val;// 节点的值TrieNode(){num = 1;son = new TrieNode[SIZE];isEnd = false;}}Trie() // 初始化字典树{root = new TrieNode();}// 建⽴字典树public void insert(String str) // 在字典树中插⼊⼀个单词{if (str == null || str.length() == 0){return;}TrieNode node = root;char[] letters = str.toCharArray();//将⽬标单词转换为字符数组for (int i = 0, len = str.length(); i < len; i++){int pos = letters[i] - 'a';if (node.son[pos] == null) //如果当前节点的⼉⼦节点中没有该字符,则构建⼀个TrieNode并复值该字符 {node.son[pos] = new TrieNode();node.son[pos].val = letters[i];}else//如果已经存在,则将由根⾄该⼉⼦节点组成的字符串模式出现的次数+1{node.son[pos].num++;}node = node.son[pos];}node.isEnd = true;}// 计算单词前缀的数量public int countPrefix(String prefix){if(prefix==null||prefix.length()==0){return-1;}TrieNode node=root;char[]letters=prefix.toCharArray();for(int i=0,len=prefix.length(); i<len; i++){int pos=letters[i]-'a';if(node.son[pos]==null){return 0;}else{node=node.son[pos];}return node.num;}// 打印指定前缀的单词public String hasPrefix(String prefix){if (prefix == null || prefix.length() == 0){return null;}TrieNode node = root;char[] letters = prefix.toCharArray();for (int i = 0, len = prefix.length(); i < len; i++){int pos = letters[i] - 'a';if (node.son[pos] == null){return null;}else{node = node.son[pos];}}preTraverse(node, prefix);return null;}// 遍历经过此节点的单词.public void preTraverse(TrieNode node, String prefix){if (!node.isEnd){for (TrieNode child : node.son){if (child != null){preTraverse(child, prefix + child.val);}}return;}System.out.println(prefix);}// 在字典树中查找⼀个完全匹配的单词.public boolean has(String str){if(str==null||str.length()==0){return false;}TrieNode node=root;char[]letters=str.toCharArray();for(int i=0,len=str.length(); i<len; i++){int pos=letters[i]-'a';if(node.son[pos]!=null){node=node.son[pos];}else{return false;}}//⾛到这⼀步,表明可能完全匹配,可能部分匹配,如果最后⼀个字符节点为末端节点,则是完全匹配,否则是部分匹配return node.isEnd;}// 前序遍历字典树.public void preTraverse(TrieNode node){if(node!=null){System.out.print(node.val+"-");for(TrieNode child:node.son){preTraverse(child);}}}public TrieNode getRoot(){return this.root;}public static void main(String[]args){Trie tree=new Trie();String[]strs= {"banana","band","bee","absolute","acm",};String[]prefix= {"ba","b","band","abc",};for(String str:strs){tree.insert(str);}System.out.println(tree.has("abc"));tree.preTraverse(tree.getRoot());System.out.println();//tree.printAllWords();for(String pre:prefix){int num=tree.countPrefix(pre);System.out.println(pre+"数量:"+num);}}}View Code 执⾏结果截图:三、简单应⽤ 下⾯讲⼀个简单的应⽤,问题是这样的: 现在有⼀个英⽂字典(每个单词都是由⼩写的a-z组成),单词量很⼤,⽽且还有很多重复的单词。

Trie树与哈希表的比较字符串存储和查找的对比分析

Trie树与哈希表的比较字符串存储和查找的对比分析

Trie树与哈希表的比较字符串存储和查找的对比分析Trie树与哈希表的比较:字符串存储和查找的对比分析在计算机科学领域的算法和数据结构中,字符串存储和查找是一项重要的任务。

为了提高存储和查找的效率,许多数据结构被设计和应用。

其中,Trie树和哈希表是两种常见的数据结构,它们都可以用于字符串存储和查找。

本文将对Trie树和哈希表进行比较,并进行对比分析。

一、Trie树的概述Trie树,也称为字典树或前缀树,是一种多叉树结构。

它的每个节点代表一个字符,从根节点到叶子节点的路径表示一个字符串。

Trie 树的特点是可以高效地插入和查找字符串,尤其适用于大量字符串查找的场景。

二、哈希表的概述哈希表,也称为散列表,是一种根据关键字直接访问存储位置的数据结构。

它通过哈希函数将关键字映射到存储位置,并在该位置存储对应的值。

哈希表的特点是查找速度快,适用于快速查找关键字的场景。

三、存储和插入效率比较在字符串存储方面,Trie树和哈希表有一些区别。

对于Trie树,每个节点都可能存在多个子节点,每一个节点代表一个字符,因此Trie树在存储字符串时需要较多的额外空间。

而哈希表则直接存储键值对,不需要额外的空间。

在插入字符串时,Trie树需要逐个字符地进行插入操作,时间复杂度为O(m),其中m为字符串长度。

而哈希表只需要通过哈希函数计算出存储位置,并将对应的值插入到该位置,插入时间复杂度为O(1)。

因此,从存储和插入效率来看,哈希表相对Trie树更加高效。

四、查找效率比较在字符串查找方面,Trie树相比哈希表具有一定的优势。

对于Trie 树,我们可以通过前缀匹配的方式,快速地查找到具有相同前缀的字符串。

这在搜索自动补全、单词检索等场景下非常有用。

而哈希表则需要进行全局搜索,比较每个字符串的值,效率较低。

然而,并非任何情况下Trie树都比哈希表更优。

当存储的字符串较为简短、数量较少或者重复较多时,哈希表的查找效率可能更高。

前缀树的应用及优化

前缀树的应用及优化

前缀树的应用及优化前缀树(Trie Tree),也叫字典树或者前缀树,是一种用于有效地存储和检索字符串的数据结构。

它的主要特点是将一系列字符串按照共同的前缀进行存储,从而提高字符串的检索效率。

本文将探讨前缀树的应用领域以及一些优化方法,以帮助读者更好地理解和使用前缀树。

一、前缀树的应用领域前缀树在实际应用中具有广泛的使用场景,主要包括以下几个方面。

1. 单词查找前缀树非常适合用于存储词典中的单词,并支持高效的查找操作。

通过将单词按照字母顺序插入前缀树中,可以快速找到满足给定前缀的所有单词,或者判断一个字符串是否为一个有效的单词。

2. 字符串匹配在文本处理、自然语言处理等领域,经常需要在大量的字符串中进行匹配操作。

前缀树可以将这些字符串按照前缀进行存储,使得匹配操作更加高效。

例如,在搜索引擎中,用户输入的关键词可以通过前缀树快速地找到相关的网页。

3. 自动补全前缀树在自动补全功能中有着广泛的应用。

当用户输入一个字符串时,前缀树可以快速找到以该字符串为前缀的所有可能补全项,从而提供更好的用户体验。

4. IP地址匹配在网络路由中,需要将目标IP地址与一组前缀进行匹配,以确定数据包的转发路径。

前缀树可以用于高效地存储和检索IP地址前缀,从而加速路由查找过程。

二、前缀树的优化方法虽然前缀树在上述应用领域中表现出色,但是在处理大规模数据时,其空间复杂度和查询时间复杂度较高。

为了进一步优化前缀树的性能,可以采取一些优化方法。

1. 压缩存储由于前缀树每个节点都包含所有可能的字符,导致节点的空间浪费。

一种常见的优化方法是使用压缩存储技术,如前缀树的压缩字典树(Compressed Trie)或者(Distributed Trie)。

这些方法通过合并具有相同前缀的节点,减少了树的深度,从而降低了存储空间的需求。

2. 前缀树的剪枝在实际应用中,有些前缀可能很少出现,可以将这些不常用的分支从前缀树中剪掉,减少了查询时不必要的遍历。

前缀树的应用和限制

前缀树的应用和限制

前缀树的应用和限制前缀树,也称为字典树或Trie树,是一种常见的数据结构,用于高效地存储和查询字符串集合。

在本文中,我们将探讨前缀树的应用场景以及其在某些情况下的限制。

一、前缀树的应用1. 字符串搜索和匹配前缀树最常见的应用场景之一是进行字符串搜索和匹配。

通过将所有字符串构建成前缀树,我们可以快速地搜索特定前缀的字符串,或者判断一个字符串是否存在于集合中。

例如,在自动完成功能中,用户可以输入部分关键字,前缀树可以迅速找到匹配的候选单词。

2. 单词查找和排序前缀树可以用于字典中单词的查找和排序。

通过将所有单词插入到前缀树中,我们可以根据特定前缀找到以该前缀开头的所有单词。

此外,前缀树还可以用于对单词进行字典序排序,因为前缀树的结构本身就可以保证按照字典序排列。

3. IP地址和路由查找前缀树在网络路由和IP地址查找中也有广泛的应用。

通过将IP地址分割成前缀的形式,并将前缀插入到前缀树中,我们可以很方便地进行IP地址的查找。

这种方式在路由表中特别有效,可以快速找到与给定IP地址匹配的最长前缀。

4. 拼写检查和纠错前缀树可以用于拼写检查和纠错。

通过将所有正确的单词插入前缀树中,我们可以根据用户输入的单词快速检查其是否拼写正确。

如果用户输入的单词在前缀树中不存在,我们可以根据相似度算法提供纠错建议。

二、前缀树的限制1. 内存消耗前缀树的主要限制之一是占用大量内存。

当存储的字符串集合很大时,前缀树的内存消耗也会相应增加。

这主要是因为每个节点都需要存储字符和指向子节点的指针,而大规模的节点数量将增加内存的使用。

2. 构建时间复杂度构建一个前缀树的时间复杂度取决于插入的字符串数量和长度。

当插入的字符串集合很大时,构建前缀树可能需要较长的时间。

这在实际应用中需要注意,特别是在输入数据频繁变动的场景下。

3. 存储冗余前缀树的存储结构会导致一定程度的存储冗余。

每个节点都需要存储字符和指针,因此对于重复出现的前缀,会有多个节点存储相同字符的情况。

单词查找树

单词查找树

单词查找树树—基本概念2010-05-19 16:02:32 阅读184 评论0 字号:大中小订阅在进行文法分析的时候,通常需要检测一个单词是否在我们的单词列表里。

为了提高查找和定位的速度,通常都要画出与单词列表所对应的单词查找树,其特点如下:(1)根节点不包含字母,除根节点外每一个节点都仅包含一个大写英文字母;(2)从根节点到某一节点,路径上经过的字母依次连起来所构成的字母序列,称为该节点对应的单词。

单词列表中的每个词,都是该单词查找树某个节点所对应的单词;(3)在满足上述条件下,该单词查找树的节点数最少。

例:图一的单词列表对应图二的单词查找树对一个确定的单词列表,请统计对应的单词查找树的节点数(包括根节点)输入格式:一个单词列表,每一行仅包含一个单词和一个换行/回车符。

每个单词仅由大写的英文字符组成,长度不超过63个字符。

文件总长度不超过32K,至少有一行数据。

输出格式:仅包含一个整数和一个换行/回车符。

该整数为单词列表对应的单词查找树的节点数。

样例输入AANASPASASCASCIIBASBASIC样例输出13分析:这里让我们对建树的过程有一个了解,就像上述过程描述的方式一样,每插入一个字符串,我们从根开始往下搜索,找到一条尽量长的与插入串前缀相吻的路径,最后搜到找不到吻合的时候,插入串的最后部分在树中生成一条独立的路径。

上述算法是可以AC的。

还有一个优化。

我们发现前缀相同的字串,他们在根据最长前缀在树中插入或走的路径大致吻合,这样我们把前缀尽量相同的字串放在一起,对比处理,不用建树就可以通过路径区别做到,没有公共前缀的字串他们是不关联的。

这种摆放需要排序,保证按字符串大小排升序,然后模拟迭代配对。

Program word;Vara:array[1..6700]of string; tmp:string;last:string;n,i,j,ans:longint;Beginassign(input,'word.in');reset(input); assign(output,'word.out');rewrite(output);while not eof dobegin inc(n);readln(a[n]);end;for i:=1 to n-1 dofor j:=i+1 to n doif a[i]>a[j] thenbegin tmp:=a[i];a[i]:=a[j];a[j]:=tmp;end;last:=a[1];inc(ans,length(a[1]));for i:=2 to n dobeginj:=1;while (j<=length(last))and(j<=length(a[i])) and(last[j]=a[i][j]) do inc(j);inc(ans,length(a[i])-j+1);last:=a[i];end;inc(ans);writeln(ans);close(input);close(output);End.{找到另人题解/muyunhai/blog/item/58779dc292103130e5dd3bc4.html} {我的题解}vart,i,j:integer;a:array[0..100] of string;max,l,n:integer;procedure pai;vari,j:integer;s:string;beginfor i:=1 to n-1 dofor j:=i to n doif a[i]>a[j] thenbegins:=a[i];a[i]:=a[j];a[j]:=s;end;end;procedure int;vari,j,w:integer;begini:=1; readln(w);readln(a[i]);l:=length(a[i]);max:=l;repeatinc(i);readln(a[i]);l:=length(a[i]);if max<l then max:=l;until i=w;n:=w;end;procedure main;var i,j:integer;k:integer;beginfor i:=1 to max dofor j:=1 to n dobeginl:=length(a[j]);if l>=i then beginif a[j][i]<>a[j-1][i] then inc(t);if (a[j][i]=a[j-1][i]) then begink:=i;while (a[j][k]=a[j-1][k])and(k>0) dodec(k);if k<>0 theninc(t);end;end;end; end;beginassign(input,'int.txt');reset(input);int;close(input);pai;main;write(t+1);end.tree.inAANASPASASCASCIIBASBASICtree.out13Trie树就是字符树,其核心思想就是空间换时间。

Trie-单词查找树

Trie-单词查找树

Trie—单词查找树一、简介Trie,又称单词查找树、前缀树,是一种哈希树的变种。

应用于字符串的统计与排序,经常被搜索引擎系统用于文本词频统计。

含有单词“tea”“tree”“A”“ZSU”的一棵Trie。

●性质⏹根节点不包含字符,除根节点外的每一个节点都只包含一个字符。

⏹从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。

⏹每个节点的所有子节点包含的字符都不相同。

●优点⏹查询快。

对于长度为m的键值,最坏情况下只需花费O(m)的时间;而BST最坏情况下需要O(m log n)的时间。

⏹当存储大量字符串时,Trie耗费的空间较少。

因为键值并非显式存储的,而是与其他键值共享子串。

⏹Trie适用于“最长前缀匹配”。

●操作⏹初始化或清空遍历Trie,删除所有节点,只保留根节点。

●插入字符串1. 设置当前节点为根节点,设置当前字符为插入字符串中的首个字符;2. 在当前节点的子节点上搜索当前字符,若存在,则将当前节点设为值为当前字符的子节点;否则新建一个值为当前字符的子节点,并将当前结点设置为新创建的节点。

.3. 将当前字符设置为串中的下个字符,若当前字符为0,则结束;否则转2.查找字符串搜索过程与插入操作类似,当字符找不到匹配时返回假;若全部字符都存在匹配,判断最终停留的节点是否为树叶,若是,则返回真,否则返回假。

●删除字符串首先查找该字符串,边查询边将经过的节点压栈,若找不到,则返回假;否则依次判断栈顶节点是否为树叶,若是则删除该节点,否则返回真。

●实现对于字符表大小为S的字符串集,需建立一个S叉树来代表这些字符串的集合。

字典树(TrieTree)讲解与实现

字典树(TrieTree)讲解与实现

字典树(TrieTree)讲解与实现 字典树,⼜称单词查找树,,是⼀种,是⼀种哈希树的变种。

典型应⽤是⽤于统计,排序和保存⼤量的字符串(但不仅限于字符串),所以经常被搜索引擎系统⽤于⽂本词频统计。

它的优点是:利⽤字符串的公共前缀来节约,最⼤限度地减少⽆谓的字符串⽐较,查询效率⽐⾼。

字典树与字典很相似,当你要查⼀个单词是不是在字典树中,⾸先看单词的第⼀个字母是不是在字典的第⼀层,如果不在,说明字典树⾥没有该单词,如果在就在该字母的孩⼦节点⾥找是不是有单词的第⼆个字母,没有说明没有该单词,有的话⽤同样的⽅法继续查找.字典树不仅可以⽤来储存字母,也可以储存数字等其它数据。

TrieNode结构定义:const int MAX = 26;typedef struct TrieNode{char *data; //储存结点数据,随需求变化bool isWord; //判断此结点前的字符串是否是⼀个单词TrieNode *branchs[MAX];};TireTree结构定义:class TrieTree{public:TrieNode *root;void initTrieTree();TrieNode *createNode();int insert(const char* word);int search(const char* word);};TireTree实现:Trie的查找(最主要的操作):(1) 每次从根结点开始⼀次搜索;(2) 取得要查找关键词的第⼀个字母,并根据该字母选择对应的⼦树并转到该⼦树继续进⾏检索; (3) 在相应的⼦树上,取得要查找关键词的第⼆个字母,并进⼀步选择对应的⼦树进⾏检索。

(4) 迭代过程…… (5) 在某个结点处,关键词的所有字母已被取出,则读取附在该结点上的信息,即完成查找。

void TrieTree::initTrieTree(){root = NULL;}TrieNode *TrieTree::createNode(){TrieNode *node = (TrieNode*)malloc(sizeof(TrieNode));node->data = NULL;node->isWord = false;for(int i = 1; i < MAX; i++)node->branchs[i] = NULL;return node;}int TrieTree::insert(const char* word) {if (root == NULL)root = createNode();TrieNode *p = root;int k = 0;while(*word){/*确定Branch ID*/if (*word >= 'a' && *word <= 'z')k = *word - 'a';else if (*word >= 'A' && *word <= 'Z') k = *word - 'A';elsereturn 0;if(p->branchs[k] == NULL){p->branchs[k] = createNode();p->branchs[k]->data = (char *)&word; }word++;if(!*word)p->branchs[k]->isWord = true;p = p->branchs[k];}// delete p;return 1;}int TrieTree::search(const char* word) {if(root == NULL)return 0;TrieNode *p = root;int k = 0;while(*word){/*确定Branch ID*/if (*word >= 'a' && *word <= 'z')k = *word - 'a';else if (*word >= 'A' && *word <= 'Z') k = *word - 'A';elsereturn 0;if(p->branchs[k] == NULL)return 0;word++;if(!*word && p->branchs[k]->isWord) return 1;p = p->branchs[k];}return 0;}测试代码:int main(int argc, char const *argv[]){TrieTree t;t.insert("ac");t.insert("abacus");t.insert("abalone");t.insert("abandon");t.insert("abandoned");t.insert("abashed");t.insert("abate");t.insert("this");if (t.search("ac"))cout<<"'ac' was found. pos: "<<endl;if (t.search("this"))cout<<"'this' was found. pos: "<<endl;if (t.search("abat"))cout<<"'abat' is found. pos: "<<endl;if (t.search("baby"))if (t.search("abacus"))cout<<"'abacus' is found. pos: "<<endl;if (t.search("baby"))cout<<"'baby' is found. pos: "<<endl;elsecout<<"'baby' does not exist at all!"<<endl; if (t.search("ac1"))cout<<"'ac1 was found. pos: "<<endl;return 0;}运⾏结果:'ac' was found. pos:'this' was found. pos:'baby' does not exist at all!。

tries try的用法

tries try的用法

tries try的用法Tries 数据结构的使用及其应用一、什么是 Tries 数据结构Tries(也被称为字典树或前缀树)是一种重要的数据结构,用于存储和查找字符串。

它提供了高效的字符串匹配和前缀搜索功能。

Tries 的核心思想是利用字符串的字符逐级构建一棵多叉树。

在每个节点上,我们将字符映射到子节点,并通过是否存在子节点来判断该字符是否出现在当前位置。

因此,不同于二叉搜索树等其他数据结构,Tries 在每个节点上存储一个完整的字符串。

二、Tries 的基本操作1. 插入操作:将一个字符串插入到 Tries 中需要遍历它所有的字符,并沿着对应路径创建和更新节点。

2. 查找操作:当需要查找一个给定的字符串时,可以从根节点开始遍历并检查每个字符是否存在于子节点中。

如果最后一个字符对应的节点存在且标记为字符串末尾,则说明该字符串存在于 Tries 中。

3. 前缀搜索操作:与查找操作类似,但不需要比较所有字符,只需检查输入字符串的部分即可。

如果输入字符串与某个路径相匹配且标记为单词结尾,则说明这个字符串是 Tries 中某些单词的前缀。

三、Tries 的应用场景1. 单词检索:Tries 的高效检索特性使其成为字典或自动补全功能的理想数据结构。

通过将单词存储在 Tries 中,并在用户输入时进行前缀搜索,可以实现快速地匹配和推荐单词。

2. IP 路由查找:Tries 可以用于构建高效的路由查找表。

将路由信息分别作为字符串的一部分存储在每个节点中,通过遍历 Tries 并寻找匹配的节点即可实现快速路由查找。

3. 字符串去重:利用 Tries 独立存储每个字符,可有效地判断一个字符串是否已存在于集合中。

这对于处理大量字符串的场景非常有用,例如大规模文本处理或数据清洗工作。

四、使用 Tries 解决问题的案例1. 实现联系人列表:我们可以使用 Tries 数据结构创建通讯录应用。

将每个联系人的姓名拆分为字符,并在 Tries 中插入相应节点。

radix树原理

radix树原理

radix树原理Radix树,也称为压缩前缀树或者基数树,是一种用于存储和快速查找字符串的数据结构。

它通过共享相同的前缀来压缩存储空间,并提供高效的插入、删除和查找操作。

Radix树的原理如下:1.Radix树由一个根节点开始,每个节点可以包含多个子节点。

每个节点代表一个字符或者字符序列,通常是一个字母或者单词。

2.从根节点到叶子节点的路径表示了一个完整的字符串。

节点之间的连接代表了字符之间的关系,使得在查找时能够沿着路径进行导航。

3.根据需要,在叶子节点处可以保存额外的数据信息。

Radix树的设计思想来自于Donald R. Morrison于1968年提出的Patricia树(Practical Algorithm To Retrieve Information Coded In Alphanumeric)。

这是一种基于二进制表示的键值的查找树,尤其适合处理非常长的、可变长度的键值。

Patricia的基本思想是构建一个二叉树,在每个节点中都存储有在进行下一次bit测试之前需要跳过的bit数目,以此来避免单路分支。

Radix树在Trie Tree(字典树)的原理上进行了优化。

Trie Tree 的原理是将每个key拆分成一个个字节,然后对应到每个分支上,分支所在的节点对应为从根节点到当前节点的拼接出的key的值。

利用上图中构造的Trie Tree,可以很方便的检索一个单词是否出现在原来的字符串集合中。

总的来说,Radix树是一种有效的数据结构,通过共享前缀来压缩存储空间,并允许快速查找、插入和删除操作。

其原理基于节点之间的关系和路径的表示方式,通过优化Trie Tree和Patricia树的设计思想,实现了高效的字符串存储和查找。

AC自动机算法详解(转载)

AC自动机算法详解(转载)

AC⾃动机算法详解(转载)⾸先简要介绍⼀下AC⾃动机:Aho-Corasick automation,该算法在1975年产⽣于贝尔实验室,是著名的多模匹配算法之⼀。

⼀个常见的例⼦就是给出n个单词,再给出⼀段包含m个字符的⽂章,让你找出有多少个单词在⽂章⾥出现过。

要搞懂AC⾃动机,先得有模式树(字典树)Trie和KMP模式匹配算法的基础知识。

KMP算法是单模式串的字符匹配算法,AC⾃动机是多模式串的字符匹配算法。

AC⾃动机和字典树的关系⽐较⼤,所以先来简单的了解下字典树Trie。

字典树⼜称单词查找树,Trie树,是⼀种树形结构,是⼀种哈希树的变种。

典型应⽤是⽤于统计,排序和保存⼤量的字符串(但不仅限于字符串),所以经常被搜索引擎系统⽤于⽂本词频统计。

它的优点是:利⽤字符串的公共前缀来减少查询时间,最⼤限度地减少⽆谓的字符串⽐较,查询效率⽐哈希树⾼。

简⽽⾔之:字典树就是像平时使⽤的字典⼀样的,我们把所有的单词编排⼊⼀个字典⾥⾯,当我们查找单词的时候,我们⾸先看单词⾸字母,进⼊⾸字母所再的树枝,然后看第⼆个字母,再进⼊相应的树枝,假如该单词再字典树中存在,那么我们只⽤花费单词长度的时间查询到这个单词。

AC⾃动机关键点⼀:字典树的构建过程:字典树的构建过程是这样的,当要插⼊许多单词的时候,我们要从前往后遍历整个字符串,当我们发现当前要插⼊的字符其节点再先前已经建成,我们直接去考虑下⼀个字符即可,当我们发现当前要插⼊的字符没有再其前⼀个字符所形成的树下没有⾃⼰的节点,我们就要创建⼀个新节点来表⽰这个字符,接下往下遍历其他的字符。

然后重复上述操作。

假设我们有下⾯的单词,she , he ,say, her, shr ,我们要构建⼀棵字典树AC⾃动机关键点⼆:找Fail指针在KMP算法中,当我们⽐较到⼀个字符发现失配的时候我们会通过next数组,找到下⼀个开始匹配的位置,然后进⾏字符串匹配,当然KMP算法试⽤与单模式匹配,所谓单模式匹配,就是给出⼀个模式串,给出⼀个⽂本串,然后看模式串在⽂本串中是否存在。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

单词查找树树—基本概念2010-05-19 16:02:32 阅读184 评论0 字号:大中小订阅在进行文法分析的时候,通常需要检测一个单词是否在我们的单词列表里。

为了提高查找和定位的速度,通常都要画出与单词列表所对应的单词查找树,其特点如下:(1)根节点不包含字母,除根节点外每一个节点都仅包含一个大写英文字母;(2)从根节点到某一节点,路径上经过的字母依次连起来所构成的字母序列,称为该节点对应的单词。

单词列表中的每个词,都是该单词查找树某个节点所对应的单词;(3)在满足上述条件下,该单词查找树的节点数最少。

例:图一的单词列表对应图二的单词查找树对一个确定的单词列表,请统计对应的单词查找树的节点数(包括根节点)输入格式:一个单词列表,每一行仅包含一个单词和一个换行/回车符。

每个单词仅由大写的英文字符组成,长度不超过63个字符。

文件总长度不超过32K,至少有一行数据。

输出格式:仅包含一个整数和一个换行/回车符。

该整数为单词列表对应的单词查找树的节点数。

样例输入AANASPASASCASCIIBASBASIC样例输出13分析:这里让我们对建树的过程有一个了解,就像上述过程描述的方式一样,每插入一个字符串,我们从根开始往下搜索,找到一条尽量长的与插入串前缀相吻的路径,最后搜到找不到吻合的时候,插入串的最后部分在树中生成一条独立的路径。

上述算法是可以AC的。

还有一个优化。

我们发现前缀相同的字串,他们在根据最长前缀在树中插入或走的路径大致吻合,这样我们把前缀尽量相同的字串放在一起,对比处理,不用建树就可以通过路径区别做到,没有公共前缀的字串他们是不关联的。

这种摆放需要排序,保证按字符串大小排升序,然后模拟迭代配对。

Program word;Vara:array[1..6700]of string; tmp:string;last:string;n,i,j,ans:longint;Beginassign(input,'word.in');reset(input); assign(output,'word.out');rewrite(output);while not eof dobegin inc(n);readln(a[n]);end;for i:=1 to n-1 dofor j:=i+1 to n doif a[i]>a[j] thenbegin tmp:=a[i];a[i]:=a[j];a[j]:=tmp;end;last:=a[1];inc(ans,length(a[1]));for i:=2 to n dobeginj:=1;while (j<=length(last))and(j<=length(a[i])) and(last[j]=a[i][j]) do inc(j);inc(ans,length(a[i])-j+1);last:=a[i];end;inc(ans);writeln(ans);close(input);close(output);End.{找到另人题解/muyunhai/blog/item/58779dc292103130e5dd3bc4.html} {我的题解}vart,i,j:integer;a:array[0..100] of string;max,l,n:integer;procedure pai;vari,j:integer;s:string;beginfor i:=1 to n-1 dofor j:=i to n doif a[i]>a[j] thenbegins:=a[i];a[i]:=a[j];a[j]:=s;end;end;procedure int;vari,j,w:integer;begini:=1; readln(w);readln(a[i]);l:=length(a[i]);max:=l;repeatinc(i);readln(a[i]);l:=length(a[i]);if max<l then max:=l;until i=w;n:=w;end;procedure main;var i,j:integer;k:integer;beginfor i:=1 to max dofor j:=1 to n dobeginl:=length(a[j]);if l>=i then beginif a[j][i]<>a[j-1][i] then inc(t);if (a[j][i]=a[j-1][i]) then begink:=i;while (a[j][k]=a[j-1][k])and(k>0) dodec(k);if k<>0 theninc(t);end;end;end; end;beginassign(input,'int.txt');reset(input);int;close(input);pai;main;write(t+1);end.tree.inAANASPASASCASCIIBASBASICtree.out13Trie树就是字符树,其核心思想就是空间换时间。

我以前用过的资料网上关于这个字典树的资料挺少的给你100000个长度不超过10的单词。

对于每一个单词,我们要判断他出没出现过,如果出现了,第一次出现第几个位置。

这题当然可以用hash来,但是我要介绍的是trie树。

在某些方面它的用途更大。

比如说对于某一个单词,我要询问它的前缀是否出现过。

这样hash就不好搞了,而用trie还是很简单。

现在回到例子中,如果我们用最傻的方法,对于每一个单词,我们都要去查找它前面的单词中是否有它。

那么这个算法的复杂度就是O(n^2)。

显然对于100000的范围难以接受。

现在我们换个思路想。

假设我要查询的单词是abcd,那么在他前面的单词中,以b,c,d,f之类开头的我显然不必考虑。

而只要找以a开头的中是否存在abcd就可以了。

同样的,在以a开头中的单词中,我们只要考虑以b作为第二个字母的……这样一个树的模型就渐渐清晰了……假设有b,abc,abd,bcd,abcd,efg,hii这6个单词,我们构建的树就是这样的。

对于每一个节点,从根遍历到他的过程就是一个单词,如果这个节点被标记为红色,就表示这个单词存在,否则不存在。

那么,对于一个单词,我只要顺着他从跟走到对应的节点,再看这个节点是否被标记为红色就可以知道它是否出现过了。

把这个节点标记为红色,就相当于插入了这个单词。

这样一来我们询问和插入可以一起完成,所用时间仅仅为单词长度,在这一个样例,便是10。

我们可以看到,trie树每一层的节点数是26^i级别的。

所以为了节省空间。

我们用动态链表,或者用数组来模拟动态。

空间的花费,不会超过单词数×单词长度。

程序非常好实现,区区几行,我就不写了,自己琢磨吧。

如果还是不懂请留言。

下面提供一个查找单词是否在给定的字典中的标程:program trie;typerec=recordGot:boolean;next:array['a'..'z'] of Longint;end;varn,i,j,Now,Tn:Longint;s:string;T:array[1..1000] of rec;flag:boolean;beginReadln(n);Tn:=1;T[1].Got:=False;fillchar(T[1].next,sizeof(T[1].next),0);for i:=1 to n dobeginreadln(s);Now:=1;for j:=1 to length(s) doif T[now].Next[s[j]]<>0 then now:=t[now].next[s[j]] elsebeginInc(Tn);T[tn].Got:=false;fillchar(T[tn].next,sizeof(T[tn].next),0);T[Now].next[s[j]]:=Tn;Now:=Tn;end;T[now].Got:=true;end;readln(s);while s<>'exit' dobeginNow:=1;flag:=true;for j:=1 to length(s) doif T[now].Next[s[j]]<>0 then now:=t[now].next[s[j]] elsebeginflag:=false;break;end;if flag thenif T[now].Got=false then flag:=false;if flag then writeln('the word is in the tree') elsewriteln('can''t find it!');Readln(s);end;end.一个单词前缀树的题,但是我却用trie树+bm算法简化版做的密码破译【问题描述】由于最近功课过于繁忙,Tim竟然忘记了自己电脑的密码,幸运的是Tim在设计电脑密码的时候,用了一个非常特殊的方法记录下了密码。

这个方法是:Tim把密码和其它的一些假密码共同记录在了一个本子上面。

为了能够从这些字符串中找出正确的密码,Tim又在另外一个本子上面写了一个很长的字符串,而正确的密码就是在这个字符串中出现次数最多的一个密码。

例如串ababa,假若密码是abab和aba,那么正确的密码是aba,因为aba在这个字符串中出现了2次。

现在你得到了Tim的这两个本子,希望你能够编写一个程序帮助Tim找出正确的密码。

【输入】输入由两个部分组成。

其中第一部分由若干行组成,每一行记录了一个密码,密码的均长度小于等于255位,并且都由小写字母组成。

然后一个空行,第二部分记录了一个很长的字符串,并且以’.’结束,其中只包含了小写字母。

【输出】输出文件名为Pass.out。

输出文件由仅有一行,为一个整数,表示正确密码在字符串中出现的次数。

如果这个出现次数为0,输出“No find”。

【样例】:Pass.in Pass.out ab 6abcbdcabcdabcabcabcdbdabcbabdbcabdbdbdbd.program pass;constfilein='pass.in';fileout='pass.out';typerec=recordwhich:Longint;Next:array['a'..'z'] of Longint;end;varo,now,i,Tn,Dn,temp,Ans:Longint;s:string;c:char;T:array[1..1000000] of REc;data:array[1..5000] of string;dLong:array[1..5000] of longint;use:array[1..5000] of boolean;d:array[1..3000000] of char;Appear:array['a'..'z'] of Longint;Long:Longint;f:boolean;function Compare(x:Longint):Longint;vars,i,Now,L,temp:Longint;begins:=0;fillchar(appear,sizeof(appear),0);L:=length(data[x]);for i:=1 to L doAppear[data[x][i]]:=i;Now:=L;while NOw<=Long dobeginif D[now]<>data[x][L] then Inc(now,L-Appear[D[now]]) elsebegintemp:=L-1;while (temp>0) and (Data[x][temp]=d[Now-(L-temp)]) do dec(temp);if temp=0 then Inc(s);Inc(Now);end;end;Compare:=S;end;procedure sort(l,r:Longint);vari,j,x:Longint;sy:string;ly:Longint;begini:=l;j:=r;x:=dLong[(l+r) div 2];repeatwhile dLong[i]<x do inc(i);while dlong[j]>x do dec(j);if i<=j thenbeginsy:=data[i];data[i]:=data[j];data[j]:=sy;ly:=dlong[i];dlong[i]:=dlong[j];dlong[j]:=ly;inc(i);dec(j);end;until i>j;if i<r then sort(i,r);if j>l then sort(l,j);end;beginfillchar(use,sizeof(use),true);fillchar(t,sizeof(t),0);Assign(input,filein);Assign(output,fileout);rewrite(output);reset(input);tn:=1;Dn:=0;while s<>'' dobeginInc(dn);data[dn]:=s;dLong[dn]:=length(s);readln(s);end;sort(1,Dn);for o:=1 to Dn dobegins:=data[o];NOw:=1;f:=true;for i:=1 to Length(s) doif t[now].Next[s[i]]<>0 thenbeginNow:=t[now].next[s[i]];if t[now].which<>0 thenbeginf:=false;breakend;end elsebeginInc(tn);t[now].next[s[i]]:=tn;now:=tn;if f then t[now].which:=o;if not f then use[o]:=false;end;Long:=0;repeatread(c);if c<>'.' thenbeginInc(Long);d[Long]:=c;end;until c='.';for i:=1 to Dn dobeginif use[i] thenbegintemp:=Compare(i);if temp>ans then ans:=temp;end;end;if ans=0 then writeln('No find') elsewriteln(Ans);close(input);close(output);end.。

相关文档
最新文档