KMP

风流意气都作罢 提交于 2020-02-25 01:45:17

KMP算法基本流程

在这里插入图片描述

核心思路:寻找回溯位置

其实便是众所皆知的使用next数组,通过next数组的保存p前后缀的交集的最大长度
例如:给定一个Pattern:abedabexa 在这里插入图片描述
默认index为0的位置的next值为0,由于下标i和j所对应的字符不同,i保存不变,j下标next值为0,j向后移一位


在这里插入图片描述
由于下标i和j所对应的字符不同,i保存不变,j下标next值为0,j向后移一位


在这里插入图片描述
由于下标i和j所对应的字符不同,i保存不变,j下标next值为0,j向后移一位


在这里插入图片描述
下标i和j对应字符相同,i,j同时向后移动一位,j下标的next值为i下标的next值+1


在这里插入图片描述
注意:下标j-1对应的next值为1,说明了,j下标前已有前缀和后缀重复的字符串,其长度为1,那么j的next值则赋为(j-1)下标的next值+1


在这里插入图片描述
重复上述思路


在这里插入图片描述
到了这里,出现了字符不匹配,那么该怎么办呢?
在这里插入图片描述
解决:下标i移至下标(i-1)所对应的next值,并继续匹配i和j所对应的字符
在这里插入图片描述
由于i与j所对应字符不相同,且i无法再继续向前移动,那么j的next值则赋为i的next值


在这里插入图片描述
由于下标i已经为0

  • 若i与j所对应字符不匹配,i无法继续向前移动只能将j对于next值赋为i的next值
  • 若i与j所对应字符相匹配,则j对应的next值则赋为i的next值+ 1

在这里插入图片描述
j下标超出数组最大下标,完成next数组的构造

代码实现

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


void GetNextArr(char* pattern, int* next, int next_len) {
	next[0] = 0;

	int i = 0;
	int j = 1;
	bool isRet = false;
	while (j < next_len) {
		if (pattern[i] == pattern[j]) {
			if (isRet) {
				next[j] = next[i] + 1;
				isRet = false;
			}
			else {
				next[j] = next[j - 1] + 1;
			}
			i++; j++;
		}
		else {
			//回退
			while (i > 0) {
				i = next[i - 1];

				if (pattern[i] == pattern[j]) {
					break;
				}

				isRet = true;
			}

			//不可回退
			if (i == 0) {
				if (pattern[i] != pattern[j]) {
					next[j++] = 0;//next[j++] = next[i];
				}
				else {
					next[j++] = 1;
				}
				isRet = false;
			}
		}
	}
}


bool KMP(char* text, char* pattern) {
	if (!text || !pattern) return false;

	int t_len = strlen(text);
	int p_len = strlen(pattern);
	int* next = new int[p_len];

	GetNextArr(pattern, next, p_len);

	int i = 0, j = 0;

	while (i < t_len && j < p_len) {
		if (text[i] == pattern[j]) {
			i++; j++;
		}
		else if (j == 0) {
			i++;
		}
		else {
			j = next[j - 1];
		}
	}

	if (j == p_len) {
		return true;
	}

	delete[] next;

	return false;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!