字符串匹配问题:给定两个字符串S(主串)和T(模式串),假设n=strlen(S) > strlen(T)=m,判断主串S中是否包含模式T,且返回T在S中所在的起始位置。这里为简单起见,若S包含T,则只返回第一个T所在的位置。
一般的蛮力法如下:
蛮力法在遇到不匹配时,j每次都要回到T的起点,从新开始匹配,这样来看效率就比较低,蛮力法的时间复杂度是O(n*m)。
1、理论
1.1、模式串T中的信息
(3)
void getNext(char T[], int next[])
{
next[1] = 0; //从第一个位置开始
int j = 1, k = 0; //这里比较巧妙,先不用管什么意思,在相关的地方验证一下,然后就会明白了
while (j < T[0])
{
if ((k == 0) || (T[j] == T[k]))
{
j++;
k++;
next[j] = k;
}
else
k = next[k]; //往前找
}
}
2、KMP完整算法
int calLen(char *p) //计算字符数组长度
{
int count = 0;
while (*(++p) != '\0') //从第一个位置开始
{
count++;
}
return count;
}
void getNext(char T[], int next[])
{
next[1] = 0; //从第一个位置开始
int j = 1, k = 0; //这里比较巧妙,先不用管什么意思,在相关的地方验证一下,然后就会明白了
while (j < T[0])
{
if ((k == 0) || (T[j] == T[k]))
{
j++;
k++;
next[j] = k;
}
else
k = next[k]; //往前找
}
}
#include<iostream>
using namespace std;
#define STR_LEN 52
int main(int argc, char* argv[])
{
int i = 1, j = 1;
char S[STR_LEN], T[STR_LEN];
int next[STR_LEN];
cout << "输入源字符串:" << endl;
cin >> S + 1; //第0个位置用于存储长度
cout << "输入目标字符串:" << endl;
cin >> T + 1;
T[0] = calLen(T);
S[0] = calLen(S);
if (T[0] > S[0] || T[0] == 0 || S[0] == 0)
{
cout << "字符串格式输入错误!" << endl;
system("pause");
return 0;
}
getNext(T, next);
while (S[i] && T[j]) //判断字符串是否结束
{
if (S[i] == T[j])
{
i++;
j++;
}
else //将T向右滑动
{
j = next[j]; //将计算出来的k赋值给j
if (j == 0) //如果j==0,表明刚刚在j==1处(即一开始)两个字符串就不相等,那么S中的i要往右移动一位
{
i++;
j++;
}
}
}
if (T[j] == '\0')
cout << "找到目标子串,从S中的第" << i - T[0] << "个位置开始!" << endl;
else
cout << "没有匹配的目标子串!" << endl;
system("pause");
return 0;
}