BK树详解

  • BK树介绍

BK树是一种基于树的数据结构,被设计于快速查找近似字符串匹配,比方说拼写检查器,或模糊查找,当搜索”aeek”时能返回”seek”和”peek”。

首先了解一下Levenshtein距离,我们通常叫它“编辑距离”。字符串A到B的编辑距离是指,只用插入、删除和替换三种操作,最少需要多少步可以把A变成B。

  • 如何建树

建树的过程有些类似于Trie。首先我们随便找一个单词作为根(比如GAME)。以后插入一个单词时首先计算单词与根的Levenshtein距离:如果这个距离值是该节点处头一次出现,建立一个新的儿子节点;否则沿着对应的边递归下去。例如,我们插入单词FAME,它与GAME的距离为1,于是新建一个儿子,连一条标号为1的边;下一次插入GAIN,算得它与GAME的距离为2,于是放在编号为2的边下。再下次我们插入GATE,它与GAME距离为1,于是沿着那条编号为1的边下去,递归地插入到FAME所在子树;GATE与FAME的距离为2,于是把GATE放在FAME节点下,边的编号为2。

  • 举例:

考虑字典集合:{“help”,“hell”,“hello”}。因此,对于这一字典集合,我们的BK树将如下所示。
在这里插入图片描述
BK树中的每个节点都只有一个具有相同编辑距离的子节点。如果我们在插入时遇到编辑距离的某些冲突,我们将向子集传播插入过程,直到找到字符串节点的适当父节点。

BK树中的每个插入都将从根节点开始。根节点可以是字典中的任何单词。

例如,在上面的字典中添加另一个单词“shell”。现在Dict [] = {“help”,“hell”,“hello”,“shell”}。现在显而易见的是,“shell”具有与“hello”相同的编辑距离来自根节点“help”,即2.因此,我们遇到了碰撞。因此,我们通过在预先存在的冲突节点上递归地执行此插入过程来处理此冲突。

因此,现在我们不是在根节点“help”处插入“shell”,而是将它插入到碰撞节点“hello”。现在新的节点“shell”被添加到树中,它的节点“hello”作为其父节点,edge-weigth为2(编辑距离)。下图描述了插入后的BK树。

在这里插入图片描述
所以,到现在为止,我们已经了解了如何构建我们的BK树。现在,问题是如何找到拼写错误的单词最接近的正确单词?首先,我们需要设置容差值。此容差值只是从拼写错误的单词到字典中正确单词的最大编辑距离。因此,要在容差限度内找到符合条件的正确单词,Naive方法将迭代字典中的所有单词并收集容差限制内的单词。但是这种方法具有O(n * m * n)时间复杂度(n是dict []中的单词数,m是正确单词的平均大小,n是拼写错误单词的长度),对于较大的字典大小超时。

因此,可以用BK树解决这一问题。我们知道BK树中的每个节点都是根据其父节点的编辑距离度量构建的。因此,我们将直接从根节点到达容差限制内的特定节点。让我们说,我们的容差限制是TOL,当前节点与拼写错误的单词的编辑距离是dist。因此,现在不是迭代它的所有子节点,而是迭代它在范围内具有编辑距离的子节点 [dist-TOL,dist + TOL]。这将在很大程度上降低我们的复杂性。我们将在时间复杂度分析中讨论这个问题。

  • 如何查找?

考虑下面构造的BK树。

加粗样式
假设我们有一个拼写错误的单词“oop”,容差限制为2.现在,我们将看到我们将如何收集给定拼写错误单词的预期正确值。

  1. 迭代1:我们将开始检查根节点的编辑距离。D(“oop” - >“help”)= 3.现在我们将迭代其编辑距离范围[D-TOL,D + TOL],即[1,5]
  2. 迭代2:让我们从最高可能的编辑距离中开始迭代,即节点“循环”与编辑距离4.现在我们将再次从拼写错误的单词中找到它的编辑距离。D(“oop”,“loop”)= 1。这里D = 1,即D <= TOL,所以我们将“循环”添加到预期的正确单词列表并处理其子节点的编辑距离在[D-TOL,D + TOL]中,即[1,3]
  3. 迭代3:现在,我们处于节点“troop”。我们将再一次检查拼写错误单词的编辑距离。 D(“oop”,“troop”)= 2.再次D <= TOL,因此我们再次将“troop”添加到预期的正确单词列表中。

对于从根节点开始直到最底部叶节点的[D-TOL,D + TOL]范围内的所有单词,我们将继续相同。这类似于树上的DFS遍历,有选择地访问边缘权重在某个给定范围内的子节点。

因此,最后我们将只留下拼写错误的单词“oop”的2个预期单词,即{“loop”,“troop”}

参考文章:戳一戳

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值