数据结构——Trie树(字典树)

目录

一、什么是字典树

问题引入: 

解法

1.暴力

2.奇奇怪怪的解法

二、字典树

1.思路

2.基本操作

(1)更新 update

(2)查找 find

3.思考

三、模板题


一、什么是字典树

问题引入: 

有n个字符串,每个字符串都由26个小写英文字母构成,现在请求出这些字符串的最长前缀

输入样例:

3

exit

apple

exford

输出样例:

2

样例输出解释:

最长公共前缀为ex,长度为2

注:若无相同前缀,则输出0

 

请自行思考10min,思考很重要

//************************************************思考线

 

 

解法

1.暴力

强行匹配每一个,只要有一个不相同就输出0,否则就不断更新最短前缀

我的解法是每次取相邻两个字符串,取得前缀长度,与下一次比较,取最小值,然后继续

做(n-1)次

 

2.奇奇怪怪的解法

这个解法是我在考场想出来的,很奇怪!

首先给这些字符串以字典序排序(大小无所谓)

然后可以给这些字符串纵向分层,相同字母为一层,变成一个节点,最后拥有多个子节点(>1)的节点层数即为所求

 

将奇奇怪怪的解法总结、提升一下就是字典树

  

二、字典树

1.思路

将若干个字符串中的每一个字符丢进一棵树中,对于这棵树而言有更新、查找(一个字符串出现次数)的作用(我觉得拓展一下有更多作用)。怎么丢进去以及怎么查找在后面会说,先来看看字典树长什么样:

【此处以输入样例举例:exit、apple、exford】

数据结构——Trie树(字典树)_第1张图片

观察这幅图可以得出以下结论:

1.一个节点最多的子节点数是可以确定的(如果是十进制数字则为10,如果是字母则为26)

2.根结点为空

3.从上至下可以读出单词(eg:从e这个节点出发读到叶节点有exit/exford两个单词,如果一个单词是另一个单词的前缀,那么需要自己标记一下)

4.字典树中字母的存储方式有两种:用边存、用点存

 

2.基本操作

(1)更新 update

思路:

先介绍一下字典树上每个节点的编号方式

对于一个节点有两个信息:该节点的每个儿子(为了查询复杂度降为O(1),这里用空间换时间,请结合后面放出的代码以及存储方式理解)、这个点的编号

则,我们用t[i][j]=k表示 编号为i的 编号为j的孩子 的编号为k

此处i、k都是编号、j也可以理解为一种编号

编号后的trie树如下图:(这个编号与读到字符串的顺序有关,请注意看输入样例的顺序)

数据结构——Trie树(字典树)_第2张图片

代码:

void update(string s)
{
	int len=s.size();//需要更新的字符串长度
	int pos=0;//表示当前位置的节点编号
	for(int i=0;i

一定要结合编号方式、图、代码来看,联动有助于理解

 

(2)查找 find

思路:

具体方法和更新一样,不过没有未出现的新的节点那一段,加了一段为找到该字符串的判断

代码:

int find()
{
	int len=s.size();
	int pos=0;
	for(int i=0;i

 

3.思考

如果每一个节点的信息多加上一个深度应该怎么办(代码在这里就不贴了,方法有很多种)

 

三、模板题

POJ 3630

POJ 1251

 

希望能对您有所帮助

 

你可能感兴趣的:(字符串,C++,数据结构,字符串)