kmp和扩展kmp code

依据上篇的kmp和扩展kmp原理书写的代码



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

void Kmp(const char *A, const char *B)
{
	int lenA = strlen(A); 
	int lenB = strlen(B);
	int *next = (int *)malloc(lenB * sizeof(int));
	
	/* next[i]为满足B[i-z+1..i] == B[0..z-1]的最大的z值, 且要求 z < i + 1 
	 * 例:B = "abab"; next[] = {0, 0, 1, 2};
	 */
	next[0] = 0;
	for (int i = 1, j = 0; i < lenB; i++) {
		while (j > 0 && B[i] != B[j]) 
			j = next[j - 1];
		if (B[i] == B[j])
			j++;
		next[i] = j;
	}

	/* ex[i]为满足A[i-z+1..i] == B[0..z-1]的最大的z值 
	 * 例:B = "abab"; next[] = {0, 0, 1, 2};
	 * A = "ababacba"; ex[] = {1, 2, 3, 4, 3, 0, 0, 1};
	 */
	int *ex = (int *)malloc(lenA * sizeof(int));
	for (int i = 0, j = 0; i < lenA; i++) {
		while (j > 0 && A[i] != B[j]) 
			j = next[j - 1];
		if (A[i] == B[j]) 
			j++;
		ex[i] = j;
		
		if (j >= lenB)
			j = next[j - 1];
	}
	
	printf("Kmp:\n");
	for (int i = 0; i < lenB; i++) {
		printf("%d ", next[i]);
	}
	printf("\n");
	
	for (int i = 0; i < lenA; i++) {
		printf("%d ", ex[i]);
	}
	printf("\n");
}
	
void ExtendKmp(const char *A, const char *B)
{
	int lenA = strlen(A); 
	int lenB = strlen(B);
	int *next = (int *)malloc(lenB * sizeof(int));
	
	/* next[i]为满足B[i..i+z-1] == B[0..z-1]的最大的z值 
	 * 例:B = "abab"; next[] = {4, 0, 2, 0};
	 */
	next[0] = lenB;
	for (int i = 0; i < lenB - 1; i++) {
		if (B[i] != B[i + 1]) {
			next[1] = i;
			break;
		}
	}
	
	int a = 1;
	for(int k = 2; k < lenB; k++) {
		int p = a + next[a] - 1, L = next[k - a];
		
		if (k - 1 + L < p)
			next[k] = L;
		else {  
			int i = (p - k + 1) > 0 ? ( p - k + 1) : 0;  
			while(k + i < lenB && B[k + i] == B[i])
				i++;  
			next[k] = i;  
			a = k;   
		}
	}   
   
   
   /* ex[i]为满足A[i..i+z-1] == B[0..z-1]的最大的z值 
	* 例:B = "abab"; next[] = {4, 0, 2, 0};
	* A = "ababacba"; ex[] = {4, 0, 3, 0, 1, 0, 0, 1};
	*/
	int minlen = lenA < lenB ? lenA : lenB;
	int *ex = (int *)malloc(lenB * sizeof(int));
	for (int i = 0; i < minlen; i++) {
		if (A[i] != B[i]) {
			ex[0] = i;
			break;
		}
	}	
 
	/* 已知 next[0..lenB] 和 ex[0..k-1],求ex[k]
	 * 前面的匹配过程中到达的最远位置p,p = max(i + ex[i] - 1) (0 <= i <= k - 1),
	 * a定义为取得最大p值时的i,则==>> A[a..p] = B[0..p-a] ==>> A[k..p] = B[k-a..p-a] 
	 * next[k-a] = L 意味着 B[k-a..k-a+L-1] = B[0..L-1] && B[L] != B[k-a+L]
	 * 当 k + L - 1 < p 时, ex[k] = L;
	 * 否则,当 i = 0..n时,依次判断A[k+L+i] 和 B[L+i] 直到两者不相等,此时ex[k] = L + i;
	 */
	a = 0;  
	for(int k = 1; k< lenA; k++){  
		int p = a + ex[a] - 1, L = next[k-a];  
		if(k - 1 + L < p)
			ex[k] = L;
		else {  
			int j= (p - k + 1) > 0 ? (p - k + 1) : 0;  
			while(k + j < lenA && j < minlen && A[k + j] == B[j]) 
				j++;  
			ex[k] = j;  
			a = k;   
		}  
	} 
	
	printf("ExtendKmp:\n");
	for (int i = 0; i < lenB; i++) {
		printf("%d ", next[i]);
	}
	printf("\n");
	
	for (int i = 0; i < lenA; i++) {
		printf("%d ", ex[i]);
	}
	printf("\n");
}

int main(int argc, char **argv)
{
	Kmp(argv[1], argv[2]);
	ExtendKmp(argv[1], argv[2]);
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值