java - 为什么朴素算法比 KMP 和 Robin-Karp 更快?
问题描述
最近我一直在研究 DNA 序列匹配算法及其比较。为了同样的目的,我已经实现了标准的 Naive、KMP 和 Robin-Karp 算法。
在 Java(8Gb RAM,Intel I5 处理器,1GB 硬盘)中执行后,我注意到 naive 的运行速度比 KMP 和 RK 快。
但是当我知道对于多达 100,000 个字符和 4 个字符的模式的 DNA 序列后,我感到惊讶,naive(6ms) 仍然优于 KMP(11ms) 和 RK(17ms)。我很困惑为什么会发生这种情况,这怎么可能?
天真的工作真的那么快还是 JVM 正在抛出一些随机垃圾值,或者我是否将 Java 的时间实例放在错误的位置?
任何帮助深表感谢。
解决方案
有许多因素可能导致这种情况。这里有几点需要考虑:
一个四字符的搜索字符串非常短——事实上,它是如此之小,以至于一个简单的搜索可能会非常快。KMP 和 Rabin-Karp 被认为是“快速”字符串搜索算法的原因是它们平均扫描输入字符串的每个字符,最多为恒定次数。如果您有一个四字符的字符串,您还将最多扫描输入的每个字符一个常数次数,这是一个低常数 (4)。所以这可能只是来自 KMP 和 Rabin-Karp 的常数因子项超过了天真的搜索的成本。(这类似于为什么许多排序算法切换到小输入大小的插入排序 - 虽然插入排序对于大序列更差,但它比小输入上的“快速”排序算法快得多。
对于从基因组中提取的四字符序列,有 4 4 = 256 种可能的随机字符串组合可供搜索。因此,按照预期,您会在从正在搜索的字符串中读取最多 256 个四字符块后找到该序列。这意味着您最多需要读取 1024 个字符才能找到您的字符串,因此基因组长度为 100,000 个字符的事实可能无关紧要。您可能更准确地处理接近 1000 的“有效”字符串长度,并且像第 (1) 部分一样,如果您对算法的输入较小,则 KMP 和 Rabin-Karp 的好处相对于它们增加的常数因子会减少。
这也可能是代码实现方式的产物。您使用的是哪个版本的 KMP 和 Rabin-Karp?
String.indexOf
JVM 实现者可能对它进行了大量优化;您是否同样使用高度优化的 KMP 和 Rabin-Karp 版本?
推荐阅读
- python - 如何在 python 中访问字典的第二个元素?
- javascript - Cypress.io 在自定义登录命令中发出异步请求
- android - Appium - 无法在字段中输入文本
- java - 我正在制作一个应用程序,我需要使用 Parcelable 接口,但面临问题,不知道如何实现它
- c# - C# 我应该将 bool 初始化为 false 还是应该在 else 语句中将其设为 false?最佳实践?
- r - 使用 R 在逻辑回归中将交互的特定组合作为变量
- python - Qtreewidget Pyqt5如何恢复正常?
- microsoft-graph-api - 团队 listChannel Graph API 导致“未经授权的错误 - “无法执行 Aad 后端请求 GetUsersByObjectIdsRequest”
- html - 如何使具有定位元素的块响应?
- python - 尝试从 Gmail 中阅读具有特定主题的电子邮件