字符串匹配之KMP算法

369 阅读2分钟

1. 原理分析

a b a a b c a c d
a b a c

i = 3, j = 3


  • 用 i 表示匹配数组的下标
  • 用 j 表示被匹配模板数组的下标
  • 当 i 能一一匹配时,i++
  • 当 i 不能匹配时,不后退 i,根据 next 数组中的值(记录要移动到的位置)来更改 j
a b a a b c a c d
a b a c

i = 3, j = 1


  • 继续对比 i 和 j 对应的值
  • 若不匹配,继续根据 next 数组中的值来更改 j
a b a a b c a c d
a b a c

i = 3, j = 0


  • 若 i 和 j 还是不匹配,则 i 前进一格



2. next 数组代码原理

next 数组是根据模板数组的内容之间的关系而确立的
 设 b = ['a', 'b', 'c', 'a', 'b', 'c', 'a', 'a', 'c']
 则 next[0] = [-1],   next[1] = 0,
 next[2] 根据 b[0] 和 b[1] 来确定, b[0] != b[1], 故 next[2] = 0
 next[3] 根据 b[0] 和 b[2] 来确定, b[0] != b[2], 故 next[3] = 0
 
 next[4] 根据 b[0] 和 b[next3] 来确定, b[0] == b[3], 故 next[4] = 1, 
 且后面要从 b[next[4]](1) 作为比较值
 next[5] 根据 b[1] 和 b[4] 来确定, b[1] == b[4], 故 next[5] = 2
 next[6] 根据 b[2] 和 b[5] 来确定, b[2] == b[5], 故 next[5] = 3
 next[7] 根据 b[3] 和 b[6] 来确定, b[3] == b[6], 故 next[5] = 4
 
 next[8] 根据 b[4] 和 b[7] 来确定, b[4] != b[7], 
 则说明长链 abcaa 断掉, 故新链要满足……ax(……a 与 next[4] 的链要能匹配, a-x 为比较的项,
 可不同,当不同时则再继续断链,直到没找到匹配链),
 在 next[4] 中的匹配链为 ab(b0b1), 故 b[7] 跟 b[2](b[b[4]])进行匹配;
 b[7] != b[2], 且 next[2] 中没有匹配链,则找 next[0], 故 next[8] = 0;

// 算法实现:
// P为结构体,里面包含 str 字符串和 length 长度
void getNext(Strs *P, int next[])
{
	int i = 1;
	int j = 0;
	next[0] = -1;
	next[1] = 0;
	while(i < P->length-1){
		if(P->str[i] == P->str[j]){
			i++;
			j++;
			next[i] = j;
		}else if(j == 0){
		    next[i+1] = 0;
		}else{
			j = next[j];

		}
	}
}




#include <stdio.h>
#include<string.h>
#include<stdlib.h>

typedef struct STRS{
    char t[50];
    int length;
}Strs; 

void getNext(int *, Strs *);
int KMPindex(Strs *, Strs *, int *);

int main(){
    Strs *string1, *string2;
    int next[10], pos;
	string1 = (Strs *)malloc(sizeof(Strs));
	string2 = (Strs *)malloc(sizeof(Strs));

    printf("请输入主串\n");
    scanf("%s", string1->t);
    string1->length = strlen(string1->t);
    printf("请输入子串\n");
    scanf("%s", string2->t);
    string2->length = strlen(string2->t);

    getNext(next, string2);
    pos = KMPindex(string1, string2, next);
    if(pos){
        printf("%d", pos);
    }else{
        printf("不存在");
    }
    return 0;
}

void getNext(int *next, Strs *string)
{
    int i=1, j=0; 
    next[0] = -1;
    next[1] = 0;
    while(i<string->length)
    {
        if(string->t[i] == string->t[j])
        {
            i++;
            j++;
            next[i] = j;
        }else if(j == 0)
            i++;
        else
            j = next[j];
    }
}

int KMPindex(Strs *string1, Strs *string2, int *next)
{
    int i=0, j=0;
    while(i < string1->length && j < string2->length)
    {
        if(string1->t[i] == string2->t[j]){
            i++;
            j++;
        }else if(j == 0){
            i++;
        }else{
            j = next[j];
        }
    }
    if(j == string2->length)
        return i-string2->length;
    return -1;
}