什么是最快的子串搜索算法?

好吧,所以我不听起来像一个白痴,我要更明确地陈述问题/要求:

> Needle(pattern)和haystack(要搜索的文本)都是C样式的空终止字符串。不提供长度信息;如果需要,必须计算。
>函数应返回指向第一个匹配的指针,如果未找到匹配,则返回NULL。
>不允许出现故障。这意味着任何具有非常量(或大常量)存储要求的算法都需要具有用于分配失败的后备情况(并且在后备保护中的性能由此有助于最坏情况性能)。
>实现是在C,虽然一个很好的描述的算法(或链接到这样)没有代码也很好。

…以及我的意思是“最快”:

>确定性O(n)其中n = haystack长度。 (但是如果它们与更鲁棒的算法组合以给出确定性的O(n)结果,则可以使用通常为O(nm)(例如滚动散列)的算法的想法。
>从不执行(可测量; if(!needle [1])等的几个时钟是可以的)比天真的强力算法,特别是在非常短的针可能是最常见的情况下。 (无条件的重预处理开销是不好的,因为试图以牺牲可能的针为代价来提高病理针的线性系数。)
>给定任意的针和干草堆,与任何其他广泛实施的算法相比或更好的性能(不比搜索时间长50%更长)。
>除了这些条件,我离开“最快”的开放式定义。一个好的答案应该解释为什么你认为你建议“最快”的方法。

我的当前实现运行在大约10%慢8倍之间(取决于输入)比glibc的双向的实现。

更新:我目前最优的算法如下:

>对于长度为1的针,请使用strchr。
>对于长度为2-4的针,使用机器字来一次比较2-4个字节,如下所示:以16位或32位整数以位移预加载针,并从每个干草堆中循环旧字节输出/新字节迭代。 haystack的每个字节只读一次,并检查0(字符串的结尾)和一个16或32位比较。
>对于长度大于4的针,使用具有坏的移位表(例如Boyer-Moore)的双向算法,其仅应用于窗口的最后一个字节。为了避免初始化1kb表的开销,这对许多中等长度的针是一个净损失,我保留一个位数组(32字节)标记在移位表中哪些条目被初始化。未设置的位对应于从不出现在针中的字节值,对于其可以进行全针长度移位。

我心里留下的大问题是:

>有没有办法更好地利用坏移位表? Boyer-Moore通过向后扫描(从右到左)来充分利用它,但是Two-Way需要从左到右的扫描。
>我发现对于一般情况(没有内存不足或二次性能条件),只有两个可行的候选算法是Two-WayString Matching on Ordered Alphabets.但是有没有容易检测的情况下,不同的算法将是最佳的?当然,空间算法中的许多O(m)(其中m是针长度)可以用于m <100左右。如果针对可证明仅需要线性时间的针的简单测试,则也可以使用最坏情况二次方程的算法。
奖励积分:

>你能通过假设针和干草堆都是良好形式的UTF-8提高性能吗? (使用不同字节长度的字符,形式良好的在针和干草堆之间施加一些字符串对齐要求,并且当遇到不匹配的头字节时允许自动2-4字节移位,但是这些约束买了很多/最大后缀计算,好的后缀移位等等已经给你各种算法?)

注意:我知道大多数算法,只是不知道他们在实践中表现如何。这里是一个很好的参考,所以人们不会继续给我参考的算法作为评论/答案:http://www-igm.univ-mlv.fr/~lecroq/string/index.html

建立一个可能的针和干草堆的测试库。描述几种搜索算法的测试,包括强力。选择与您的数据表现最佳的一个。

Boyer-Moore使用具有良好后缀表的坏字符表。

Boyer-Moore-Horspool使用坏字符表。

Knuth-Morris-Pratt使用部分匹配表。

Rabin-Karp使用运行散列。

他们都交易开销,以减少比较到不同的程度,所以真实世界的性能将取决于针和干草堆的平均长度。初始开销越大,输入越长,开销越大。用非常短的针,蛮力可能赢。

编辑:

不同的算法可能最适合查找碱基对,英语短语或单个字。如果对于所有输入有一个最佳算法,它将被公开。

想想下面的小表。每个问号可能有不同的最佳搜索算法。

                 short needle     long needle
short haystack         ?               ?
long haystack          ?               ?

这应该是一个图,在每个轴上有一个范围更短到更长的输入。如果您在这样的图上绘制每个算法,每个算法都会有不同的签名。一些算法在模式中遭受很多重复,这可能影响像搜索基因的用途。影响整体性能的一些其它因素是不止一次地搜索相同的模式并且同时搜索不同的模式。

如果我需要一个样本集,我想我会刮掉一个网站,如谷歌或维基百科,然后从所有的结果页面剥离html。对于搜索网站,输入一个单词,然后使用建议的搜索短语之一。选择几种不同的语言(如果适用)。使用网页,所有的文本将是短到中等,所以合并足够多的页面来获得更长的文本。你还可以找到公共领域的书籍,法律记录和其他大型文本。或者只是通过从字典中挑选单词来生成随机内容。但是,分析的要点是针对您要搜索的内容类型进行测试,因此如果可能,请使用真实世界的样本。

我留下短而长的模糊。对于针,我认为短为8个字符以下,中等为低于64个字符,长度低于1K。对于干草堆,我认为短如2 ^ 10以下,中等在2 ^ 20以下,长达2 ^ 30个字符。

翻译自:https://stackoverflow.com/questions/3183582/what-is-the-fastest-substring-search-algorithm

转载注明原文:什么是最快的子串搜索算法?