Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm Knuth-Morris-Pratt算法中的冗余指令_Algorithm_Optimization_Knuth Morris Pratt - Fatal编程技术网

Algorithm Knuth-Morris-Pratt算法中的冗余指令

Algorithm Knuth-Morris-Pratt算法中的冗余指令,algorithm,optimization,knuth-morris-pratt,Algorithm,Optimization,Knuth Morris Pratt,目的是查找字符串中第一个(可能是下一个)出现的子字符串。由于子字符串可以包含重复部分,因此它使用某种回溯机制。这是伪代码中的算法: let m ← 0, i ← 0 while m + i < length(S) do if W[i] = S[m + i] then if i = length(W) - 1 then return m let i ← i + 1 else

目的是查找字符串中第一个(可能是下一个)出现的子字符串。由于子字符串可以包含重复部分,因此它使用某种回溯机制。这是伪代码中的算法:

let m ← 0, i ← 0
while m + i < length(S) do
        if W[i] = S[m + i] then
            if i = length(W) - 1 then
                return m
            let i ← i + 1
        else
            if T[i] > -1 then
                let m ← m + i - T[i], i ← T[i]
            else
                let i ← 0, m ← m + 1
(摘自维基百科)

现在我们可以看到,该算法只将
0
cnd
的值写入
T
。对于第一种类型的赋值,该语句非常正确。对于第二种情况,它取决于
cmd
的值

现在减少的唯一方法是使用第二种情况
(*)
,在这种情况下,cmd将变得越来越小,直到其值为零或更小。但是由于
cmd
从数组的已初始化部分获取值,因此可以是
0
-1
。如果
cmd
确实是
-1
,这将导致
T[pos]
被设置为
0
,因为在设置值之前有一个增量。如果
cmd
为零,则根本没有问题

因此,更有效的算法是:

let m ← 0, i ← 0
while m + i < length(S) do
    if W[i] = S[m + i] then
        if i = length(W) - 1 then
            return m
        let i ← i + 1
    else
        if i > 0 then
            let m ← m + i - T[i], i ← T[i]
        else
            let m ← m + 1
让m← 0,我← 0
而m+i<长度
如果W[i]=S[m+i],那么
如果i=长度(W)-1,则
返回m
让我← i+1
其他的
如果i>0,那么
让我← m+i-T[i],i← T[i]
其他的
让我← m+1

这句话对吗?如果没有,您能给出一个子字符串,其中两个或多个
-1
出现在
T
-array中吗?

这对我来说很好,尽管我不知道在实践中会有多大不同。当然,在常见场景中,大多数循环都是在
i
为0且字符位于
s[m]
≠ <代码>W[0]

我不认为维基百科中的算法是“官方的”或超优化的;这是为了说教

当遇到无法扩展任何候选匹配的字符且不是所搜索单词的第一个字符时,出现
if
的第二个分支;在这种情况下,有必要移动该角色。(这是前面提到的常见情况。)

在输入故障分支的所有其他情况下,
m+i
不变。在成功案例和最终失败案例中,
m+i
正好增加1

由于
min
max
在许多CPU上都是无分支操作码,另一种优化方法是将
T[0]
设置为
0
,而不是
-1
,并将循环更改为:

let m ← 0, i ← 0
while m + i < length(S) do
    if W[i] = S[m + i] then
        if i = length(W) - 1 then
            return m
        let i ← i + 1
    else
        let m ← m + max(1, i - T[i]), i ← T[i]

然而,作者抱怨上述简单算法效率低下,并花了几页探讨优化

毫无疑问,这是不必要的低效吗?
let m ← 0, i ← 0
while m + i < length(S) do
    if W[i] = S[m + i] then
        if i = length(W) - 1 then
            return m
        let i ← i + 1
    else
        let m ← m + max(1, i - T[i]), i ← T[i]
(* Note: here, m is the length of pattern and n is the length of the input *) j := k := 1; while j ≤ m and k ≤ n do begin while j > 0 and text[k] ≠ pattern[j] do j := next[j]; k := k + l; j := j + l; end;