算法--以KMP实现的字符串匹配

以KMP实现的字符串匹配

性质

给定模式集合,和源集合。
算法输出源集合中和模式匹配的所有相关处的起始位置。

接口设计

template
class CharacterMatch
{
public:
	CharacterMatch();
	~CharacterMatch();
public:
	DataStruct::Array::DynArray RunKMP(
		const DataStruct::Array::DynArray& arrPattern_,
		const DataStruct::Array::DynArray& arrSource_);
private:
	DataStruct::Array::DynArray PatternPreAnalysis(
		const DataStruct::Array::DynArray& arrPattern_);
};

实现

构造

template
CharacterMatch::CharacterMatch()
{

}

析构

template
CharacterMatch::~CharacterMatch()
{

}

算法运行

template
DataStruct::Array::DynArray CharacterMatch::RunKMP(
	const DataStruct::Array::DynArray& arrPattern_,
	const DataStruct::Array::DynArray& arrSource_)
{
	DataStruct::Array::DynArray _arrRet;
	DataStruct::Array::DynArray _nPatternRet = PatternPreAnalysis(arrPattern_);
	int _nPreMatchLen = 0;
	int _nCurMatchLen = 0;
	for (int _i = 0; _i < arrSource_.GetSize(); _i++)
	{
		if (_nPreMatchLen == arrPattern_.GetSize())
		{
			_nPreMatchLen = _nPatternRet[_nPreMatchLen - 1];
		}

		if (arrSource_[_i] == arrPattern_[_nPreMatchLen])
		{
			_nCurMatchLen = _nPreMatchLen + 1;
		}
		else
		{
			_nCurMatchLen = 0;
			while (_nPreMatchLen > 0)
			{
				_nPreMatchLen = _nPatternRet[_nPreMatchLen - 1];
				if (arrSource_[_i] == arrPattern_[_nPreMatchLen])
				{
					_nCurMatchLen = _nPreMatchLen + 1;
					break;
				}
			}
		}

		_nPreMatchLen = _nCurMatchLen;
		if (_nCurMatchLen == arrPattern_.GetSize())
		{
			_arrRet.Add(_i - arrPattern_.GetSize() + 1);
		}
	}

	return _arrRet;
}

template
DataStruct::Array::DynArray CharacterMatch::PatternPreAnalysis(
	const DataStruct::Array::DynArray& arrPattern_)
{
	DataStruct::Array::DynArray _nPatternRet;
	int _nSize = arrPattern_.GetSize();
	for (int _i = 0; _i < _nSize; _i++)
	{
		int _nNum = 0;
		int _nMayNum = _i;
		for (; _nMayNum > 0; _nMayNum--)
		{
			int _nStartIndex = _i - _nMayNum + 1;
			bool _bMatch = true;
			for (int _k = 0; _k < _nMayNum; _k++)
			{
				if (arrPattern_[_nStartIndex + _k] != arrPattern_[_k])
				{
					_bMatch = false;
					break;
				}
			}

			if (_bMatch)
			{
				_nNum = _nMayNum;
				break;
			}
		}

		_nPatternRet.Add(_nNum);
	}

	return _nPatternRet;
}

算法性质&正确性证明

对输入序列每个元素进行遍历
保持记录,到上一元素位置 为止可以与 模式达成的最大匹配的长度PreMatchLen

如果PreMatchLen > 0 且 本位置元素 和 模式PreMatchLen位置元素 不匹配
易于知道,本位置为止 与模式达成的最大匹配长度
只能在 0,...,PreMathcLen中
令k=PreMatchLen-1模式序列中前PreMatchLen个元素设为 x0 x1 ... xk

当前位置i为止可与模式达成最大匹配长度 设为 len
len <= PreMatchLen
1. 从当前位置往前len-1个位置开始 到 当前位置前一位置的 len-1个输入序列元素
是模式序列中前PreMatchLen个元素设为 x0 x1 ... xk 的一个长度为len-1的前缀

2. 从当前位置往前len-1个位置开始 到 当前位置前一位置的 len-1个输入序列元素
也是模式序列中前PreMatchLen个元素设为 x0 x1 ... xk 的一个长度为len-1的后缀

首先,对于当前位置前一元素p,
我们知道 该元素p和 xk是匹配的
从p次往前的p'
从xk依次往前x'
只要往前元素个数在PreMaxLen范围
则有p' 和 x'是匹配的

len-1<= PreMaxLen-1在此范围内
故有
2的结论成立。

综合,此位置的与模式产生长度为len的最大匹配中
满足
len的前len-1个序列元素是 模式前PreMaxLen个元素序列的 后缀和前缀

经过预先处理
我们可以找到满足
模式前PreMaxLen个元素序列 即是该序列前缀又是该序列后缀的最长序列。
对该序列进行验证,
验证指的是 
假设满足要求的序列长度为t
验证即为,验证 当前位置 和 模式第t+1元素位置 是否匹配,若匹配,则验证通过。更新CurMaxLen。
验证失败,
我们需要寻找满足
对模式前PreMaxLen个元素序列 即是该序列前缀又是该序列后缀的其他可能序列。
假设 满足该要求的最长序列,经过验证不通过。
对于其他满足要求的序列
假设最长序列为 x1, ..., xa
不妨设一个满足要求的非最长序列为
x1,...,xb
b < a
模式前PreMaxLen个元素序列
x1,....,xk
x1,...,xb是x1,...,xa的前缀
x1,...,xa是x1,....,xk后缀
x1,...,xb也是x1,...,xk后缀
b < a
x1,...,xb也是x1,...,xa后缀
综合
x1,...,xb
满足既是x1,...,xa前缀又是x1,...,xa后缀
故对x1,...,xa序列验证失败后,取x1,...,xa序列最长的前缀后缀进行后续验证
并可如此迭代

如果迭代到某次,找不到序列x1,...,xz的最长前缀和后缀,则依然验证
若验证通过,PreMaxLen更新为1
若验证不通过,PreMaxLen更新为0

你可能感兴趣的:(Algorithm,&,DataStruct)