- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我发现的关于 Aho-Corasick 的所有文献和实现都是关于从一组短语预先构建整个 trie 的。但是,我对将其作为可变数据结构使用的方法很感兴趣,它可以处理偶尔的添加和删除,而无需重建整个 trie(假设其中有 100 万个条目)。如果最坏的情况很糟糕也没关系,只要平均情况接近对数。
根据我的理解,每个节点的失败状态是另一个使用相同符号的节点。因此,如果我们有一个从每个符号到使用该符号的节点列表的哈希多重映射,我们就有了失败状态需要更新的候选对象。
删除很简单。您找到使用已删除节点作为故障状态的所有其他节点并重新计算它们的故障状态。从字符串的末尾向后移动,树应该仍然处于良好状态。
添加有点棘手。任何未能达到该符号的节点都可以将新节点作为更好的候选节点。然而,再次似乎遍历具有该符号的所有其他节点并完全重新计算其失败状态。
换句话说,如果我们要添加或删除一个带有符号“A”的节点,我们需要访问 trie 中任何其他“A”节点,并重新计算失败状态(寻找其最近的祖先为“A"作为 child ,或根)。这将需要访问符号“A”的每个节点,但在我的例子中,这将比访问 trie 中的每个节点少几个数量级。
该算法是否有效,还是我遗漏了一些明显的东西?
最佳答案
我继续实现它并且它似乎正在工作。算法的更好描述,包括图片:https://burningmime.gitlab.io/setmatch/implementation-overview.html#supporting-add-remove-in-an-aho-corasick-trie
为了后代(以及根据 StackOverflow 政策),我已将其复制到此处:
It supports modification (add/remove) instead of being built all at once from a pre-set dictionary. This isn't mentioned in any literature about it, and all the open-source implementations I've seen of it have followed in that respect. It turns out that supporting add and remove operations to an AC automaton is fairly trivial. For deep tries over a small alphabet, it would not be very time-efficient, but luckily we have a shallow trie over a large alphabet.
We store a hash multimap of each token to every node that uses that token. When we remove a phrase, we start from the last (bottom-most) node. We remove the pointer to the phrase from this bottom-most node. Then, if it has any children, we can't delete any more. Otherwise, go through each other node that uses this node as a fail state and recompute its fail state. Finally, delete the node, then go up to the node's parent and do the same process. We'll eventually reach either a node that has another phrase output, a child, or the root node.
That's kind of difficult to picture, so consider this trie (stolen from the Wikipedia article). We're going to remove the string caa (light gray color), which will require that the fail states in yellow be updated:
The result:
Note there are cases where a node's fail state might be updated 2 or more times in the same remove operation, but will eventually be correct. This could be avoided by removing everything first, then going back through tokens, but the code is complicated enough as it is, and that would only provide a performance benefit in certain awkward circumstances, while being a performance hit in the average case. We just assume that strings containing the same token more than once are rare.
Adding a node is slightly more difficult, but can make use of the same hash multimap structure. Each time a node is added, every other node in the trie that uses the same token and is at a lower depth than the added node could need to have its fail state updated to the new node.
To help picture that, imagine going from the second diagram back to the first diagram. The same two fail states are the ones who would need to be updated if adding the string caa back into that trie, and since we recompute every c and a node, it's not a problem.
We could keep track of the node depths to skip over about half, but right now it's just recomputing the fail state for every node that shares the token to save memory. This means that tries where the tokens appear many times will be slow to add to, but again that's considered a rare enough situation. It would be a concern if you were trying to adapt this technique to something like a DNA sequence or antivirus database where there is a small alphabet.
The time complexity depends on how many nodes share symbols and how deep the trie is, meaning it's worst-case O(N), but in practice a fairly small number (average-case is roughly O(log^2 N) ).
难以置信的困惑和大部分未注释的代码,但如果你好奇,这里是 the header , the body , 和 some tests
关于database - 面对插入和删除更新 Aho-Corasick trie,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53288664/
有一个 servlet 代码用于将 excel/zip 文件从生产服务器下载到本地计算机。当我单击生产服务器上的“保存”或“打开”按钮时,它会抛出 ClientAbortException。相同的代码
在我的搜索页面中,默认情况下我使用 page=0 进行分页。并在 asyncData 方法中使用此参数调用 api。但不知何故,该值增加了一个。 所以这是我的网址,例如, http://localho
任何人都可以解释下面这段代码,我正在努力弄清楚。 order = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1357902468' pr
我正在 Java 平台上开发一个实时战略游戏克隆,我有一些概念性的问题关于放置在哪里以及如何管理游戏状态。游戏使用Swing/Java2D作为渲染。在目前的开发阶段,没有模拟,也没有人工智能,只有用户
这个问题在这里已经有了答案: Simple Linux Signal Handling (5 个答案) 关闭 8 年前。 我的应用程序已经配置了一个 SIGTERM 处理程序。例如: Signal(
我正在尝试创建一个会在几秒钟后淡入视野的文本,但我遇到了问题。淡入 View 效果很好,但文本在显示后几乎立即消失。其次我需要这个动画以延迟的方式工作,但是当我设置延迟时它似乎没有任何区别。延迟在早些
我正在尝试在我的项目 pubspec.yaml 中添加 flutter_svg: ^0.5.1 并面临以下问题。 依赖flutter_svg >=0.0.2 需要Flutter SDK版本>=0.3.
我在使用 Go 的 sync.Map 时遇到问题。以下是详细信息: 我创建了一个全局同步 map ,如下所示: var MySyncGlobalMap = sync.Map{} 在一个事件中,我用预期
12月9日,Apache 基金会针对一个名为 Log4Shell 的关键零日漏洞发布了紧急更新,这个在Log4j(一个用于各种Java应用的开源日志框架)中发现的漏洞被认定为CVE-2021-442
DNS 劫持作为最常见的网络攻击方式,是每个站长或者运维团队最为头疼的事情。苦心经营的网站受到 DNS 劫持后,不仅会影响网站流量、权重,还会让用户置身于危险之中,泄露隐私造成财产损失。 就是这样
我遇到过使用 Vision Framework 进行真人脸检测的问题。我在下面提到了苹果链接。 https://developer.apple.com/documentation/vision/tra
我是 MySQL 的新手,一直遇到一些错误,但我总能找到解决方案,除了这个,我不知道如何解决它。 如果变量“ue”为 1 或 0(一堆存在验证),则以下 MySQL 过程返回一个值。验证部分 (SET
我的应用程序出现此错误: java.lang.IllegalArgumentException: method ID not in [0, 0xffff]: 65536 我知道这是由于单个 dex 文
我必须对几乎在发送的每个请求中都使用 javax.faces.FormSignature 的应用程序进行负载测试。我正在使用这样的 xPath 提取器来获取 FormSignature 的值: /ht
屏幕上有 6 个开关控件。一次只能启用一个开关。如果第 5 个开关打开,则一个标签和一个文本字段应该可见或者隐藏。 当 5 开关从关闭变为打开并再次变为关闭时,我遇到了问题。标签和提交的文本应该被隐藏
当我将它应用于主体颜色或更改字体大小时,它工作正常,但当涉及到使元素 float 或 flex-direction 时,它根本不回应。尝试了所有可能的方法,只是不确定这里有什么问题:请检查代码,我认为
我希望我能得到一些关于如何解决这个问题的信息。我是 jenkins 的新手,正在尝试设置 jenkins 服务器。 启用 SSL 后,我无法登录 Jenkins。 Chrome 抛出错误 ERR_SS
我的项目是 EJB3 上的 java 项目,使用 Hibernate 和 Weblogic 服务器。 为了方便起见(据我所知,hibernate 很典型),一些实体包含循环依赖(父知道子,子知道父)。
@Autowired和@Resource都是Java Spring框架中的注解,用于实现依赖注入(DI)和控制反转(IoC)。它们的区别主要在以下三个方面: 源头不同 @Autowir
我正在使用下面的插件来自动管理补丁版本。 id "com.zoltu.git-versioning" version "3.0.3" 基本上,上述插件需要使用 v.major.minor 约定标记代码
我是一名优秀的程序员,十分优秀!