您将使用哪种算法在短文本中搜索短子串?简而言之,我的意思是子串为5-10个字符,字符串为255。我正在考虑根据输入数据长度选择算法。对于更长的输入,哪种算法更好?
答案 0 :(得分:5)
试试Turbo-BM。但是,IMO用这种短串通常的线性扫描就足够了。
答案 1 :(得分:1)
如果您正在寻找比Boyer Moore更好的算法,那么您需要一个混合答案。
据我所知,只有后缀树在文本搜索中击败了Boyer Moore。但是,它使用更多时间来创建索引并使用更多磁盘空间。
其他信息: 速度方面,后缀树或后缀数组击败了任何版本的Boyer Moore,因为后缀树基本上实现了树中所有可能的搜索,如数据结构。
然而,后缀树的内存成本较高,索引文本的速度较慢(创建树数据结构)。
Boyer Moore与后缀树的速度差异: Boyer Moore在搜索文本上是线性的。 后缀树在搜索模式上是线性的。
如果您在200个字符的文本上搜索5个字母的单词,那么boyer moore会执行200个操作,而后缀树会执行5个字母。
然而,它可能更快,实施起来非常困难。在数据结构的难度规模上,它可能是最难的一个。一旦建成,它可以针对空间和速度进行大幅优化。
这就是说,在未来几年寻找后缀树。 通常,后缀树用于DNA索引和Web搜索引擎优化。
Boyer Moore无处不在,例如会议程序(文本搜索功能),广泛用于网络搜索引擎。
答案 2 :(得分:1)
@anon @Anton Gogolev
用一个词回答你的问题:
Railgun_Quadruplet
这个C函数在短2,3,4个模式和160个字符的字符串上进行了大量测试,在这个表http://www.sanmayce.com/Railgun/index.html#Heavy-Search-Hustle上查看,你可以自己决定。
一篇文章也在: http://www.codeproject.com/KB/cpp/Railgun_Quadruplet.aspx
答案 3 :(得分:0)
您可以尝试Suffix Trees或Suffix Arrays。两者都取决于模式长度。
答案 4 :(得分:0)
我认为通过这种变化可以使Boyer-Moore-Horspool更快(我不知道它的名字,也许是我的名字:-)。 BMH算法不使用匹配的字符和不匹配的字符信息。它仅使用当前图案位置中的最后一个文本字符。例如:
在BMH中,下一个位置是(C与下一个C对齐):
Text : TTTTZBCTTTTTTTTTTTTT
Pattern: ABCCABC
Text : TTTTZBCTTTTTTTTTTTTT
Pattern: ABCCABC
如果我们使用匹配的字符,则下一个位置是(BC与下一个BC对齐):
Text : TTTTZBCTTTTTTTTTTTTT
Pattern: ABCCABC
Text : TTTTZBCTTTTTTTTTTTTT
Pattern: ABCCABC
如果我们使用匹配的字符和不匹配的字符,则下一个位置是(BC与下一个BC对齐,但是由于不匹配的图案字符A与该下一个BC的前一个字符相同,也不会匹配。由于没有其他BC,因此跳过是模式长度):
Text : TTTTZBCTTTTTTTTTTTTT
Pattern: ABCCABC
Text : TTTTZBCTTTTTTTTTTTTT
Pattern: ABCCABC
这是Java实现(仍可以改进),使用风险自负,因为我尚未对其进行全面测试。在我的性能测试中,Boyer-Moore-Horspool总的来说仍然胜过此实现。但是如预期的那样,如果模式被重用(两种模式都没有模式预处理),则此实现会成功。
public static int[] processPattern1(char[] pattern) {
int[] skip = new int[256];
for (int i = 0; i < skip.length; ++i) {
skip[i] = pattern.length;
}
for (int i = 0; i < pattern.length - 1; ++i) {
skip[pattern[i]] = pattern.length - i - 1;
}
return skip;
}
public static int[] processPattern2(char[] pattern) {
int[] skip = new int[pattern.length];
int i, j, k, x, y;
int lpos = pattern.length - 1;
int l2pos = pattern.length - 2;
OUTER:
for (k = l2pos; k > -1; k--) { // k points to unmatched pattern character
j = k + 1;
for (i = k; i > 0; i--) {
if (pattern[i] == pattern[j] && pattern[i-1] != pattern[k]) {
for (x = i + 1, y = j + 1; y < pattern.length && pattern[x] == pattern[y]; x++, y++) {
}
if (y == pattern.length) {
skip[k] = pattern.length - x;
continue OUTER;
}
}
}
for (x = lpos - j; x > -1; x--) {
if (pattern[x] == pattern[lpos]) {
for (i = x - 1, y = l2pos; i > -1 && pattern[i] == pattern[y]; i--, y--) {
}
if (i == -1) {
skip[k] = lpos - x;
continue OUTER;
}
}
}
skip[k] = pattern.length;
}
return skip;
}
public static int search(char[] text, char[] pattern, int[] skip1, int[] skip2) {
int k = pattern.length - 1;
int i, j;
int lpos = k;
int l2pos = pattern.length - 2;
while (k < text.length) {
if (text[k] == pattern[lpos]) {
for (j = l2pos, i = k - 1; j > -1 && text[i] == pattern[j]; j--, i--) {
}
if (j == -1) {
return i + 1;
}
k += skip2[j];
} else {
k += skip1[text[k]];
}
}
return -1;
}
public static void main(String[] args) {
String origText = "TTTTTTTTTTTTTTTZBCRABCCABCTTTTTTTTTTTTT";
char[] pattern = "ZBCRABCCABC".toCharArray();
char[] text = origText.toCharArray();
int[] skip1 = processPattern1(pattern);
int[] skip2 = processPattern2(pattern);
System.out.println(search(text, pattern, skip1, skip2) == origText.indexOf(pattern));
}
答案 5 :(得分:0)
以下是我上面代码的改进。在我的测试中,它与BMH并驾齐驱,但在某些运行中会大获全胜(每次运行是对39,650个字符的英语文档的随机位置进行1,000,000次搜索)。
public class BoyerMoore {
int[] tab1 = new int[256];
int[][] tab2 = new int[1000][1001];
int[] tab3 = new int[1000];
public BoyerMoore8() {
for (int i = 0; i < tab1.length; i++) {
tab1[i] = -1;
}
}
public void processPattern(char[] pattern) {
// tab1 structure,
// 0 => tab2 index
// tab2 structure,
// 0 - pattern length - 2 => skip values
// pattern length - 1 => default skip value
// pattern length => pattern position where to start comparing
int i, p;
int lp = pattern.length - 1;
for (i = 0; i < pattern.length; ++i) {
tab3[i] = tab1[pattern[i]];
tab1[pattern[i]] = i;
}
for (i = pattern.length - 2; i > -1; i--) {
if (i < tab1[pattern[i]]) {
continue;
}
p = tab1[pattern[i]];
tab2[p][lp] = lp - i;
tab2[p][pattern.length] = i - 1;
computeJump(pattern, p, i + 1, tab2[p][lp]);
}
computeJump(pattern, tab1[pattern[lp]], pattern.length, 0);
}
public void computeJump(char[] pattern, int index, int len, int defJump) {
int i, k, x, y;
int lpos = len - 1;
int l2pos = len - 2;
int p = tab3[lpos];
OUTER1:
for (k = 0; k < lpos; k++) { // k points to unmatched pattern character
i = tab3[k + 1];
OUTER2:
while (i > 0) {
if (pattern[i - 1] != pattern[k]) {
x = k + 2;
y = i + 1;
while (x < len) {
if (pattern[y++] != pattern[x++]) {
i = tab3[i];
continue OUTER2;
}
}
tab2[index][k] = (len - y) + defJump;
continue OUTER1;
} else {
i = tab3[i];
}
}
x = l2pos - k;
while (p > x) {
p = tab3[p];
}
i = p;
OUTER3:
while (i > -1) {
x = l2pos;
y = i - 1;
while (y > -1) {
if (pattern[y--] != pattern[x--]) {
i = tab3[i];
continue OUTER3;
}
}
tab2[index][k] = (lpos - i) + defJump;
continue OUTER1;
}
tab2[index][k] = len + defJump;
}
}
public int search(char[] text, char[] pattern) {
int k = pattern.length - 1;
int i, j, p;
int lpos = k;
int l2pos = k - 1;
OUTER:
while (k < text.length) {
p = tab1[text[k]];
if (p == -1) {
k += pattern.length;
continue OUTER;
} else {
if (text[k] == pattern[lpos]) {
for (j = l2pos, i = k - 1; j > -1; j--, i--) {
if (text[i] != pattern[j]) {
k += tab2[p][j];
continue OUTER;
}
}
return i + 1;
} else {
for (j = tab2[p][pattern.length], i = k - 1; j > -1; j--, i--) {
if (text[i] != pattern[j]) {
k += tab2[p][j];
continue OUTER;
}
}
k += tab2[p][lpos];
continue OUTER;
}
}
}
return -1;
}
public int search(String origText, String origPattern) {
char[] text = origText.toCharArray();
char[] pattern = origPattern.toCharArray();
processPattern(pattern);
int res = search(text, pattern);
for (int i = 0; i < pattern.length; i++) {
tab1[pattern[i]] = -1;
}
return res;
}
}
答案 6 :(得分:0)
这是另一种方法,可能会击败BMH。这与BMH类似,但会继续将最后一个文本字符之后的后续文本字符对齐,直到当前文本字符无法对齐或不再有模式字符对齐为止。预处理将建立一个表格,该表格包含每个图案位置处任何字符的下一个位置。例如:
Pattern: ABCABC
012345
位置5的下一个C本身是5,而位置4的下一个C是2。在模式中找不到的字符的下一个位置是-1。以下是Java代码:
public class BoyerMooreHorspool {
int[] tab1 = new int[256];
int[][] tab2 = new int[1000][1000];
int[] tab3 = new int[1000];
public BoyerMooreHorspool() {
for (int i = 0; i < tab1.length; i++) {
tab1[i] = 999;
}
for (int i = 0; i < 1000; i++) {
tab2[999][i] = -1;
}
}
public void processPattern(char[] pattern) {
int i, j, p;
for (i = 0; i < pattern.length; ++i) {
tab1[pattern[i]] = -1;
}
for (i = 0; i < pattern.length; ++i) {
tab3[i] = tab1[pattern[i]];
tab1[pattern[i]] = i;
}
for (i = 0; i < pattern.length; i++) {
p = tab1[pattern[i]];
for (j = tab3[i] + 1; j < i; j++) {
tab2[p][j] = tab3[i];
}
if (i == p) {
for (j = i; j < pattern.length; j++) {
tab2[p][j] = i;
}
} else {
tab2[p][i] = i;
}
}
}
public int search(char[] text, char[] pattern) {
int k = pattern.length - 1;
int i, j, oi, ok;
int lpos = k;
while (k < text.length) {
j = k;
ok = k;
i = tab2[tab1[text[j]]][lpos];
k += lpos - i;
j--;
i--;
while (i > -1) {
oi = i;
i = tab2[tab1[text[j]]][i];
k += oi - i;
j--;
i--;
}
if (ok == k) {
return j + 1;
}
}
return -1;
}
public int search(String origText, String origPattern) {
char[] text = origText.toCharArray();
char[] pattern = origPattern.toCharArray();
processPattern(pattern);
int res = search(text, pattern);
for (int i = 0; i < pattern.length; i++) {
tab1[pattern[i]] = 999;
}
return res;
}
}