【问题标题】:KMP String Matching Algorithm stuck in a loopKMP字符串匹配算法陷入循环
【发布时间】:2015-02-02 02:11:02
【问题描述】:

我正在尝试使用 CLRS 实现 KMP 字符串匹配算法,但是由于文本输入为“bbaa”,模式输入为“aab”,它在while 循环中陷入了无限循环 @987654322 @ 功能。我的代码如下:

private int[] getKMPPrefix(char[] p, int m) {
    int[] prefix = new int[m];
    prefix[0] = 0;
    int k = 0;
    for(int q = 1; q < m; q++) {
        while(k > 0 && p[k] != p[q] ) { //Stuck here
            k = prefix[k];
        }
        if(p[k] == p[q]) {
            k++;
        }
        prefix[q] = k;
    }
    return prefix;
}

public void kmp(String text, String pattern) {
    char[] t = text.toCharArray();
    char[] p = pattern.toCharArray();
    int n = text.length();
    int m = pattern.length();

    int[] prefix = getKMPPrefix(p, m);

    int q = 0;
    for(int i = 1; i < n; i++) {
        while(q > 0 && p[q] != t[i]) {
            q = prefix[q];
        }
        if(p[q] == t[i]) {
            q++;
        }
        if(q == m) {
            System.out.println("Pattern occurs with shift " + (i-m+1));
            q = prefix[m-1];
        }
    }
}

知道为什么会这样吗?

【问题讨论】:

    标签: java string algorithm


    【解决方案1】:

    这是正在发生的事情:

    到达线:

    while(k > 0 && p[k] != p[q] ) { //Stuck here
    

    k=0 所以显然这会失败,它会跳出循环并转到下一个

    if(p[k] == p[q]) {
                k++;
            }
    

    在你的情况下,输入是aab 所以这是真的p[0]=p[1]=a

    现在,k=1

    现在您将k 的值分配给prefix

    prefix[q] = k;
    

    现在它陷入僵局。

    现在会回到while循环

     while(k > 0 && p[k] != p[q] ) { //Stuck here
                k = prefix[k];
            }
    

    注意,您刚刚在前面的循环中分配了prefix[q] = k;,即p[1] = 1

    当涉及到 while 循环 k=1 和 'p[1] != p[2]' 即 a!=b 它通过并进入循环内

    k = prefix[k];
    

    k=1prefix[1] = 1,这意味着您将值 1 重新分配给 k

    它再次回到 while 循环和 k=1p=1 的值,因为它从未经过 while 循环以递增 p

    出现死锁,while 循环的条件将保持为true,程序永远不会退出while 循环。

    您可以更改 while 循环条件或在 while 循环内增加 p 或在特定条件后在 while 内增加 break。我解释了Deadlock,尽管尝试自己弄清楚程序。祝你好运

    【讨论】:

      【解决方案2】:
      private static int[] computPrefix(String P) 
          {
              int m = P.length();
              int[] prefix = new int[m];
              prefix[0]=0; // you just mentioned this
              prefix[1]=0; // mention this in initial condition
              int k = 0;
       // start loop form i = 2. You can find the clear explanation in CLRS page number 1002
              for(int i = 2; i<m; i++)
              {
                  while(k>0 && P.charAt(k) != P.charAt(i))
                  {
                      k = prefix[k]; // NO deadlock
                  }
      
                  if(P.charAt(k)==P.charAt(i))
                  {
                      k++;
                  }
                  prefix[i] = k;
              }
              return prefix;
          }
      

      如果模式是“aabaaa”,您的代码将导致死锁。这个正确的条件将以正确的方式生成前缀。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-02-10
        • 2016-10-16
        • 2021-07-21
        • 2014-05-02
        • 1970-01-01
        • 1970-01-01
        • 2014-09-07
        • 2015-10-03
        相关资源
        最近更新 更多