线性Z-Indexing可能是目前最快的子列表搜索算法之一,其中模式相同且语料库是动态的,具有真正的O(n)复杂度(对于小字母表,它比你从O(n)中期望的表现要好得多,因为ZIndexing提供了足够的机会跳过索引):
我在中央佛罗里达大学Shaojie Zhang的遗传算法课程中编写了我的实现。我已经将算法适应于C#,特别是使用通用的
IList<T>
,如果您决定使用它,请给出信用。这些技术的研究可在
此处找到,具体来说,请查看
此处的讲义笔记。
无论如何,我已经在此处提供了代码
在TestZIndexing.cs中查看如何执行搜索的示例(在这种情况下,是在字符序列上进行搜索,但是使用泛型,您应该能够使用任何具有等号运算符的东西)。
使用方法很简单:
IEnumerable<int> LinearZIndexer.FindZ<T>(
IList<T> patternSequence, IList<T> sourceSequence, bool bMatchFirstOnly)
where T: IComparable;
而且,由于一些DNA是环形的,因此我有一个环形变体:
IEnumerable<int> LinearZIndexer.FindZCircular<T>(
IList<T> patternSequence, IList<T> sourceSequence, bool bMatchFirstOnly)
where T: IComparable;
更快速的方法:使用后缀树
如果你想要比O(n)更好的性能,可以使用后缀树来达到O(m),其中m是模式列表的大小。当模式改变而语料库保持不变时(与先前情况相反),这个方法就起作用了。在我为TestSuffixTree.cs
贡献的同一个库中查找。唯一的区别是你必须提前构建后缀树,因此它绝对适用于针对大型语料库的多模式搜索,但我为构建后缀树提供了一个O(n)和空间O(n)的算法。
调用同样简单,同样可以使用任何提供IComparable的东西:
string strTest = "bananabananaorangebananaorangebananabananabananaban";
string[] strFind = {"banana", "orange", "ban"};
var tree = new SuffixTree<char>();
tree.BuildTree(strTest.ToCharArray());
var results = tree.Find(str.ToCharArray());
foreach(var r in results) Console.WriteLine(r);
享受。
T
而不是char
。我记不清复杂度了,但肯定比已经提出的选择要好(看起来像是一种暴力方法)。 - leppie