【发布时间】:2016-02-22 22:40:30
【问题描述】:
我正在实现一个支持通配符的 KMP 字节模式搜索。下面是生成前缀表WITHOUT通配符的算法:
vector<int> PrefixFunction(string S)
{
vector<int> p(S.size());
int j = 0;
for (int i = 1; i < (int)S.size(); i++)
{
while (j > 0 && S[j] != S[i])
j = p[j-1];
if (S[j] == S[i])
j++;
p[i] = j;
}
return p;
}
上述算法的问题在于它不适用于通配符。长话短说,考虑以下数学方程:
- ∵
a = b - ∵
b = c - ∴
a = c
当不涉及通配符时,这些等式是 100% 正确的。但是,它们不适用于通配符。例如:a = 1、b = ??(?? 是通配符)和c = 2。 a equals b 和 b equals c,但 a does not equal to c
由于通配符的这种怪异特性,上面提到的算法将不起作用!因此,我必须为通配符实现一个特定的算法。 我当前的实现如下所示:
vector<int> GeneratePrefixTable(vector<int> bytes, vector<unsigned char> flags)
{
vector<int> prefixTable(bytes.size());
prefixTable[0] = 0;
for (int j = 1, m = bytes.size(); j < m; j++)
{
int largest = 0;
for (int i = 1; i < j; i++)
{
bool match = true;
for (int k = 0; k < i; k++)
{
if (bytes[k] != bytes[j - i + k + 1] && !flags[k] && !flags[j - i + k + 1])
{
//if the bytes do not match and neither of them is a wildcard
match = false;
break;
}
}
if (!match)
{
continue;
}
largest = i;
}
prefixTable[j] = largest;
}
return prefixTable;
}
变量定义:
-
vector<int> bytes模式。又名针。 -
vector<unsigned char> flags标志数组,表示某个位置的字节是否是通配符 -
j我们正在查看的模式的索引生成前缀# -
largestOne迄今为止发现的最大前缀长度 -
i我们正在测试的前缀长度
请注意,一旦发现不工作的前缀长度,我并没有停止搜索。这也是由于通配符的奇怪属性。
例如,考虑模式01 02 ?? 02 00:
- 长度为1:前缀:
1后缀:0,不匹配 - 长度为2:前缀:
1 2后缀:2 0不匹配 - 长度为3:前缀
1 2 ??后缀:?? 2 0匹配!
由于这个奇怪的属性,我必须测试每个可能的前缀长度。这进一步减慢了我的算法。有哪些方法可以加快我的前缀表生成算法?
【问题讨论】:
-
也许这会有所帮助:MoreKMP.pdf
-
上面链接下的“KMPWildcardMatch.java”不正确。失败的一个例子:
s="abczzzdXzde",p = "abc???de"。
标签: c++ algorithm wildcard string-search