Java教程

字符串专题-学习笔记:字典树(Trie 树)

本文主要是介绍字符串专题-学习笔记:字典树(Trie 树),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

目录
  • 1. 概述
  • 2. 详解
    • 2.1 Trie 树的概念
    • 2.2 Trie 树的操作
      • 2.2.1 Trie 树的存储
      • 2.2.2 Trie 树的插入-Insert
      • 2.2.3 Trie 树的查询-Find
    • 2.3 Trie 树的适用范围
  • 3. 总结

1. 概述

Trie 树,中文名为字典树,是一种字符串的高效处理算法。

Trie 树实现的功能就是快速的查找一堆字符串里面有没有某个串是另一个串的前缀,后缀等等。

2. 详解

2.1 Trie 树的概念

Trie 树首先是一棵树,比如下面这棵树就是一棵 Trie 树。

在这里插入图片描述

这棵树是由 ab,abd,ac,bd 四个字符串构成的。

那么结合图示,我们会发现 Trie 树有以下几个特点:

  1. 每个字符串一定是根节点到某个节点的路径。
  2. 根节点是虚拟节点。
  3. 红色节点表示这个字母是某个字符串的末尾。

那么根据上面这三条性质,我们就可以方便的将每一个字符串唯一的插入 Trie 树而且不引起歧义。

那么 Trie 树的操作有什么呢?要怎么实现呢?

2.2 Trie 树的操作

接下来的所有字符串,如果没有特殊说明,都只包含小写字母。

2.2.1 Trie 树的存储

我们需要一个结构体来存储 Trie 树。

Trie 树中需要包含两个变量:\(ch[],flag\),分别表示当前节点的孩子编号和当前节点是不是一个单词的节点。

特别的,0 为超级根,不会存下任何字母信息。

同时我们需要一个 \(\operatorname{init}\) 函数来初始化。

代码:

struct node
{
	int ch[26], flag;
	void init()
	{
		for (int i = 0; i <= 25; ++i) ch[i] = 0;
		flag = 0;
	}
}

2.2.2 Trie 树的插入-Insert

我们看看 Trie 树要如何插入。还是看图。

在这里插入图片描述

假设我们现在要插入字符串 acd

那么首先看第一位 a,有了,那么我们沿着 a 向下。

在这里插入图片描述

然后我们看到 c 有了,向下。

在这里插入图片描述

然后我们看 d,没有,那么我们新建一个节点 d 跟在 c 后面。

在这里插入图片描述

然后走到头了,于是标记 d 是一个单词的重点,所以最后的字典树如下。

在这里插入图片描述

Trie 树插入的代码如下:

void Insert(int k)//k 表示第 k 个字符串,采用字符数组存储,下标从 1 开始
{
	int len = strlen(a[k] + 1), p = root;
	for (int i = 1; i <= len; ++i)
	{
		int q = a[k][i] - 'a';
		if (!tree[p].ch[q])
		{
			++cnt;//计数器 +1
			tree[cnt].init();//预先初始化,多测的时候尤其有用(好像比 memset 快)
			tree[p].ch[q] = cnt;
		}
		p = tree[p].ch[q];
	}
	tree[p].flag = 1;//标记当前为一个单词的结尾
}

需要注意的是,如果字符串有重复,那么 \(flag\) 就要 +1 而不是 =1。

2.2.3 Trie 树的查询-Find

Trie 树的查询。

还是刚才那个 Trie 树。假设我们要查询 acdbda 是否存在。当然正式的时候是一个一个查询的,这里因为方便我就两个一起了。

首先看 ab,都在根节点的儿子内,那么往下走。

在这里插入图片描述

然后看 cd,都在,继续往下走:

在这里插入图片描述

最后看 da,发现 da 不在,那么可以判断 bda 不在,将 \(P_1\) 往下走。

在这里插入图片描述

最后第一个字符串遍历完了 而且 \(P_1\) 节点的 \(flag\) 为 1 (这一点很重要,因为可能出现找到了却不是个字符串的情况),那么就存在。

查询操作的代码如下:

bool Find(int k)
{
	int len = strlen(b[k] + 1), p = root;
	for (int i = 1; i <= len; ++i)
	{
		int q = b[k][i] - 'a';
		if (!tree[p].ch[q]) return 0;//节点不存在
		p = tree[p].ch[q];
	}
	if (!tree[p].flag) return 0;//这不是一个字符串
	return 1;
}

2.3 Trie 树的适用范围

Trie 树适用于那些有多个文本串和多个模式串,询问某个串是否为另一个串的 前缀 等等问题。注意 Trie 树是不能直接进行字串匹配的,需要使用一点科技,这个就是 AC 自动机解决的了。注意不是自动 AC 机

3. 总结

Trie 树形象直观,就是一个简单插入,删除的过程。

这篇关于字符串专题-学习笔记:字典树(Trie 树)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!