1. 程式人生 > >字元匹配KMP演算法

字元匹配KMP演算法

KMP是三位大牛:D.E.Knuth、J.H.Morris和V.R.Pratt同時發現的。其中第一位就是《計算機程式設計藝術》的作者!!

KMP演算法要解決的問題就是在字串(也叫主串)中的模式(pattern)定位問題。就是我們平時常說的關鍵字搜尋。模式串就是關鍵字(接下來稱它為T),如果它在一個主串(接下來稱為S)中出現,就返回它的具體位置,否則返回-1.

KMP演算法的核心就是避免不必要的回溯,不必要的回溯可以後模式串決定。KMP演算法為模式串新增一個next陣列用來指導模式匹配串下一步改用第幾號元素進行匹配。next陣列舉例:

T 9 a b a b a a a b a
下標 0 1 2 3 4 5 6 7 8 9
next X 0 1 1 2 3 4 2 2 3

假設prefix表示當前下標字元的字尾,suffix表示當前下標字元的字首,我們關注的是字首和字尾的相同字元數,由此來決定next陣列。至於字首字尾可通過下面步驟自己體會,文字感覺說不清楚。

T串第0個字元表示T串長度,對於next[0]=X,

當T[1]字元發生失配,此時next[1]=0;    當T[2]字元發生失配,此時next[2]=1

當T[3]字元發生失配,此時prefix=‘a’,suffix='b',且字首字尾不相等,此時next[3]=1

當T[4]字元發生失配,此時prefix='a',suffix='a',且字首字尾有一個相等,此時next[4]=2

當T[5]字元發生失配,此時prefix='a''b',suffix=‘a’'b',且字首字尾有兩個相等,此時next[5]=3

當T[6]字元發生失配,此時prefix='a''b''a',suffix='a''b''a',且字首字尾有三個相等,此時next[6]=4

當T[7]字元發生失配,此時prefix='a',suffix=‘a’,且字首字尾有一個相等,此時next[7]=2

當T[8]字元發生失配,此時prefix='a',suffix=‘a’,且字首字尾有一個相等,此時next[8]=2

當T[9]字元發生失配,此時prefix='a''b',suffix='a''b',且字首字尾有兩個相等,此時next[9]=3

以後為next陣列的獲取過程,程式碼如下:

void next(String T,int *next)
{
    prefix = 0;
    suffix = 1;
    next[1] = 0;
    
    while(suffix < T[0])
    {
        if(0 == prefix || T[suffix] == T[prefix])
        {
            suffix++;
            prefix++;
            next[suffix] = prefix;
        }
        else
        {
            prefix = next[prefix];
        }
    }
}

返回子串T在主串S第pos個字元之後的位置,若不存在,返回-1

#include <stdio.h>

typedef char* String;

void next(String T, int *next)
{
    int j = 0;
	int i = 1;
	next[1] = 0;

	while( i < T[0] )
	{
		if( 0 == j || T[i] == T[j] )
		{
			i++;
			j++;
			next[i] = j;
		}
		else
		{
			j = next[j];
		}
	}
}

int Index(String S, String T, int pos)
{
    int i = pos;
    int j = 1;
    int next[255];

    next(T, next);

    while(i < S[0] && j <= T[0])
    {
        if(0 == j || S[i] == T[j])
        {
            i++;
            j++;
            if(T[i] != T[j])
                next[i] = j;
            else
                next[i] = next[j];
        }
        else
        {
            j = next[j];
        }
    }

    if(j > T[0])
        return i - T[0];
    else
        return -1;
}