【问题标题】:Why naive algorithm is faster than KMP and Robin-Karp?为什么朴素算法比 KMP 和 Rabin-Karp 更快?
【发布时间】:2021-03-02 02:55:30
【问题描述】:

最近我一直在研究 DNA 序列匹配算法及其比较。为了同样的目的,我已经实现了标准的 Naive、KMP 和 Robin-Karp 算法。
在 Java 中执行后(8Gb RAM,Intel I5 处理器,1GB 硬盘),我注意到 naive 的运行速度比 KMP 和 RK 快。
但是当我知道对于多达 100,000 个字符和 4 个字符的模式的 DNA 序列后,naive(6ms) 仍然优于 KMP(11ms) 和 RK(17ms)。我很困惑为什么会发生这种情况,这怎么可能?
naive 的工作速度真的那么快还是 JVM 抛出了一些随机垃圾值,还是我将 Java 的时间实例放在了错误的位置?

非常感谢任何帮助。

【问题讨论】:

  • 您如何衡量绩效? (但话虽如此:naive 更快并非不可信。Java 的内置 String.indexOf 使用了 naive 算法,因为它在实践中大部分时间效果更好。)
  • 性能是使用 System.currentMilliSeconds() 测量的。使用标准 charAt() 函数匹配字符串的代码。
  • stackoverflow.com/q/504103/869736 解释了这种衡量性能的方式如何导致非常不准确的结果。

标签: java string algorithm pattern-matching


【解决方案1】:

有许多因素可能会导致这种情况。这里有几点需要考虑:

  1. 四个字符的搜索字符串非常短——事实上,它是如此之小,以至于一个简单的搜索可能会非常快。 KMP 和 Rabin-Karp 被认为是“快速”字符串搜索算法的原因是它们平均扫描输入字符串的每个字符,最多为恒定次数。如果您有一个四个字符的字符串,您还将最多扫描输入的每个字符一个常数次数,这是一个低常数 (4)。所以这可能只是来自 KMP 和 Rabin-Karp 的常数因子项超过了天真的搜索的成本。 (这类似于为什么许多排序算法切换到小输入大小的插入排序 - 而插入排序对于大序列更糟糕,它比小输入上的“快速”排序算法快得多。)你可能想要混合一些东西稍微增加一点,尝试不同的字符串长度、非随机输入等。

  2. 对于从基因组中提取的四字符序列,有 44 = 256 种可能的随机字符串组合可供搜索。因此,按照预期,您会在从正在搜索的字符串中读取最多 256 个四字符块后找到该序列。这意味着您最多需要读取 1024 个字符才能找到您的字符串,因此基因组长度为 100,000 个字符的事实可能无关紧要。您可能更准确地处理接近 1000 的“有效”字符串长度,并且像第 (1) 部分一样,如果您对算法的输入较小,则 KMP 和 Rabin-Karp 的优势相对于它们增加的常数因子会减少。

  3. 这也可能是代码实现方式的产物。您使用的是哪个版本的 KMP 和 Rabin-Karp? String.indexOf 可能已被 JVM 实现者高度优化;您是否同样使用高度优化的 KMP 和 Rabin-Karp 版本?

【讨论】:

猜你喜欢
  • 2019-10-18
  • 1970-01-01
  • 2018-03-07
  • 2021-11-18
  • 1970-01-01
  • 2020-03-26
  • 2022-01-18
  • 2022-01-10
  • 1970-01-01
相关资源
最近更新 更多