Trie(通常发音为“ try”)是针对特定类型的搜索进行优化的树数据结构。 当您想获取部分值并返回一组可能的完整值时,可以使用Trie。 一个典型的例子是自动完成。
上图显示了Trie的结构,以暗示其工作原理。 您可以将Trie视为一组相关值。 这些值的共同点是它们的前缀。
当您搜索更特定的前缀时,您将获得更特定的返回值。 使用上图所示的Trie,搜索与前缀“ b”的匹配项将返回6个值:be,bear,bell,bid,bull,buy。
搜索与前缀“ be”匹配的结果将返回2个值:bear,bell
何时使用Tries
只要您想将前缀与可能的完整值匹配,就可以使用Trie。 这就是Trie如何获得有趣的名字的方式。 “ Trie”一词是“ re trie val”一词的后缀。
尝试通常用于实现以下内容:
- 自动完成/提前输入
- 搜索
- 拼写检查
- 分类
您不仅限于前缀匹配的单词。 试用可以存储:
- IP地址
- 电话号码,
- 对象(您可以搜索对象的属性),
- 和更多…
您是否应该在前端应用程序中使用Tries?
在使用JavaScript固有的数据结构之前,需要考虑一些实际因素,例如:
- 这种结构是否可以提高性能? 性能提升值得吗?
- 这种结构是否易于使用-或至少不再困难?
- 这种结构是否为我的数据提供了更多的语义? 它使我的代码更容易理解吗?
- 此结构会对我的构建大小有多大影响? 这种增加的构建大小值得吗?
为了回答这些问题,我们将比较Tries和Arrays-数组是JavaScript中最常用的Collection结构。
对比的尝试和数组
注意: 各种JavaScript引擎将实现JavaScript规范。 不一样。 因此,每个环境的性能结果可能会有所不同。
这是我们用来对比Tries和Arrays的标准:
- 性能(运行时间和加载时间)
- 易于使用和可读性
- 构建大小(数组不添加任何额外的代码。我们将分析Trie。)
设定
- 我使用
create-react-app
在React中编写了快速自动完成功能。 看起来是这样的:
- 我使用Josh Jung的
trie-search
作为我的Trie实现。 - 我使用
faker
者生成了10,000个名称集。 我不在乎名称是否唯一。
码
这是自动完成的基本代码。 注意,它不使用任何特定的Collection数据结构。 下面是Trie和Array的实现细节。
这是基于数组的代码:
这是基于TrieSearch的代码:
性能
我在代码中测试了两个地方的性能:
- 将数据项加载到数据结构中。
- 在数据结构中搜索项目。
所有测试均使用Chrome 65.x进行。
加载数据项
使用Trie,您将比数组经历更长的初始化时间。 尝试以O(n * m)时间初始化。 为了让您有一个实际的认识,平均花费90毫秒将10,000个项目添加到测试代码中的Trie。 这是一次性费用。 可以(即应该)将Trie初始化推迟到页面加载完成之后。
最常见的是,您将从数组初始化Trie。 如果需要添加更多数据,则可以手动将项目添加到Trie。
当搜索是应用程序的主要重点之一时,尝试会增加价值。 由于初始化成本高,如果用户搜索量不大,使用Trie可能不适合您的应用程序。
运行
在每个测试中,我在自动完成输入中键入“ Cath”,并测量了搜索花费了多长时间。
TrieSearch的表现优于Array.filter
。 它快了50%。
使用方便
如上面的代码示例所示,使用TrieSearch并不比使用Array复杂。 但是,要记住一些差异:
有关使用TrieSearch的更多详细信息,请参阅文档 。
尺寸
TrieSearch最小为7.4kb。 它具有13个依赖项。 整个产品的构建大小约为10kb。 确定这是否会对您的应用程序产生重大影响取决于您。
摘要
当您拥有进行大量搜索的应用程序时,Trie是一种出色的数据结构。 尝试相对容易使用-而且速度很快。
在阵列上使用Trie会降低性能,例如:
- Trie初始化。 (因此,建议您将Trie的初始化推迟到页面加载之后)。
- 较大的捆束尺寸。