1 子串匹配算法
T串为待匹配的字符串;P为模式串;且 len(T)>len(P)
1.1
|
1.1.1 BF法要点
[1] 工作原理:
如果工作下标i,j对应的字符相同,那么则两个工作下标都向后移;反之j回溯到模式字符串的首字符,j回溯该轮匹配开始时j所指的字符的下一位
[2] 结果:
如果j的值等于模式串P的长度,则子串匹配成功。
[3] 缺陷:
若T串中含有多个P串,则只能找到第一个;当T串中不含有P串作为子串时,无法快速定位到P,T的最大公共子串。
1.2 KMP算法
1.2.1 KMP算法工作原理
[1] 提出KMP算法的由头
避免BF算法中在匹配失败的情况下出现的一些不必要的回溯。具体包括以下两个方面:
1) 指向T串的工作下标在每轮匹配失败后不进行回溯;
2) 指向P串的工作下标在每轮匹配失败后不一定回溯到P串首部。
完成上述两个简化的核心思想:对称前缀串
对称前缀串:和后缀重叠对称
KMP算法
#include <iostream>
#include <vector>
#include <map>
using namespace std;
#pragma once
class kmp
{
public:
kmp(wstring s1,wstring s2);//构造函数为m_traget,m_pattern赋值,长度小的定位为
void KMPMatcher();//执行KMP算法
void ComputePrefixFunction();
//void BestMatchInfo();//根据匹配的模式字符串的前缀串的长度,将匹配信息排序
void GetMatchInfo(vector< pair<int,int>>&matchinfo );
~kmp(void);
private:
wstring m_target;//带匹配的目标字符串
wstring m_pattern;//匹配的模式串
//map<int,int> matchinfo;//保存两个字符串之间的匹配信息
//第一个int 保存目标串的下标,第二个int 是匹配的长度
//vector<pair<int,int>> bestmatch;//目标字符串和模式字符串的最优匹配程度第一个int保存的是目标字符串的结尾位置,第二个字符串是两个串之间匹配上的最大字串
int *prefixInfo;
int *matchInfo;//目标字符串中每个位置所匹配上的模式子串的最末一位下标
};
#include "StdAfx.h"
#include "kmp.h"
/************************************************************************/
/* 构造函数,根据长度来确定哪个串是目标串,哪个串是模式串 */
/************************************************************************/
kmp::kmp(wstring s1,wstring s2)
{
if (s1.size()>=s2.size())
{
m_pattern=s2;
m_target=s1;
}
else
{
m_pattern=s1;
m_target=s2;
}
int itssize=m_pattern.size()+1;
prefixInfo=new int[itssize];
memset(prefixInfo,-1,itssize*sizeof(int));
itssize=m_target.size()+1;
matchInfo=new int[itssize];
memset(matchInfo,-1,itssize*sizeof(int));
}
kmp::~kmp(void)
{
delete prefixInfo;
delete matchInfo;
}
/************************************************************************/
/* 获得模式串中符合要求的前缀的最后一位下标 */
/************************************************************************/
void kmp:: ComputePrefixFunction()
{
int m=m_pattern.size()+1;
const wchar_t*P=m_pattern.c_str();
prefixInfo[0]=-1;
int k=-1;
for (int q=1;q<m;q++)
{
while (k>-1 && P[k+1]!=P[q])
{
k=prefixInfo[k];
}
if (P[k+1]==P[q])
{
k++;
}
prefixInfo[q]=k;
}
}
/************************************************************************/
/* 执行KMP算法 */
/************************************************************************/
void kmp::KMPMatcher()
{
const wchar_t*P=m_pattern.c_str();
const wchar_t*T=m_target.c_str();
int m=wcslen(P)+1;
int n=wcslen(T)+1;
ComputePrefixFunction();
int q=-1;//起始赋值为非法下标
for (int i=0;i<n;i++)
{
while(q>-1&&P[q+1]!=T[i])
{
q=prefixInfo[q];
}
if(P[q+1]==T[i])
{
q++;
if (matchInfo[i]==-1)
{
matchInfo[i]=q;
}
}
if (q==m-1)
{
q=prefixInfo[q];
}
}
}
/************************************************************************/
/* */
/************************************************************************/
void kmp::GetMatchInfo(vector< pair<int,int>>&matchinfo )
{
for (int i=0;i<=m_target.size();i++)
{
matchinfo.push_back(make_pair(i,matchInfo[i]));
}
}