模式串 從 0 開始的KMP算法

/**
 *  看了 b站視頻 BV1jb411V78H 對KMP有了一點理解,而後我寫了這個代碼
 *  這個代碼和視頻裏面的有一點不一樣,字符串是從 0 開始的,而不是從1 開始的
 *  但願可以幫到學習KMP的人
 */


#include <stdbool.h>
#include <malloc.h>
#include "KMP.h"

// KMP.h 內容
/*
#define MAXSIZE (255)

typedef struct {
    char ch[MAXSIZE + 1];
    int length;
}SString;

void Next(SString const *t);
extern int *next;
int IndexOf_KMP(SString const *s, SString const *t);
*/

int *next;      // 計算 next數組

/**
 * 計算 0-based 模式串t的next數組
 * @param t 模式串
 */
void Next(SString const *t) {
    //  模式串 0 開始
    int length = t->length;

    // 分配 next數組 所須要的空間
    next = (int *)malloc(sizeof(int) * length);
    for (int *p = next; p < next + length; p++)
    {
        *p = 0;
    }

    for (int i = 0; i < length; i++)
    {
        if (i <= 1)     // 前兩個next[i]置爲-1
        {
            next[i] = -1;
            continue;
        }

        // 執行下面的語句的時候, 必定有 i >= 2



        int maxlen = 0;         // 存儲最長公共先後綴的長度

        /**
         *  // len 表示前綴或後綴的最大長度, 可取的值是 [1..i-1]      // i 爲(模式串或next數組)的訪問下標
         *  這裏主要是 對 模式串在i位置 求 它的最大公共先後綴的長度
         *  從 1 開始 到 i-1 一個一個去試 
         *  
         */
        for (int len = 1; len < i; len++)
        {
            int val = 0;
            bool flag = false;

            for (int j = 0, k = i - len; j < len; j++, k++)
            {
                if (t->ch[j] == t->ch[k])
                {
                }
                else
                {
                    flag = true;        // len 長度的公共先後綴匹配失敗
                    break;
                }
            }

            if (flag == false)          //  公共先後綴長度爲len
                val = len;
            if (val > maxlen)           // 這個比較不是必須的,由於找公共先後綴的長度的時候, len 從 1 到 i-1
                maxlen = val;           // maxlen 就是 next[i]的值了
        }
        next[i] = maxlen;
    }
}

// 調用這個函數以前,必定要調用 Next函數,爲模式串構建 next數組
int IndexOf_KMP(SString const *s, SString const *t)
{
    // 開始匹配

    int i = 0, j = 0;       // i 表示主串的下標, j 表示模式串的下標
    while (i < s->length)
    {
        if (j == -1 || s->ch[i] == t->ch[j])
        {
            i++;
            j++;
        }
        else
        {
            j = next[j];
        }

        // 匹配成功
        if (j == t->length)
        {
            return i - t->length;
        }
    }

    // 匹配失敗
    return -1;
}
相關文章
相關標籤/搜索