字符串匹配問題:給定兩個字符串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;
}