算法原理:http://wiki.jikexueyuan.com/project/kmp-algorithm/define.html
#include<iostream>
#include<string>
#include<string.h>
using namespace std;
//给定两个字符串,判断其中一个是否包含另一个,如果包含则返回起始位置
//next[i]的含义是,i位之前的字符串拥有的最长前缀和最长后缀相同的长度。
//最长前缀:是说以第一个字符开始,但是不包含最后一个字符。
//KMP的原理在于,将暴力破解中重复的遍历用一个NEXT数组记录模式串前缀和后缀相同的方式记录下来
//匹配失败后可以从最长前缀跳到最长后缀,中间可跳是因为:
//如果存在其他相同的字符串,那么前缀和后缀相同的数目就会增大,这与得到的相同最长前缀和后缀相矛盾
//
int getIndexOf(string s, string m){ //传入两个字符串
//s原字符串 m 匹配字符串
//边界条件判断
if (s.empty() == 1 || m.empty() == 1 || m.length() < 1 || s.length() < m.length()){
return -1;
}
//字符串变为字符数组
char ss[100];
strncpy_s(ss, s.c_str(), s.length());
////
//for (int i = 0; i< s.length(); i++){
// std::cout << ss[i];
//}
//std::cout<< std::endl;
////
char ms[100];
strncpy_s(ms, m.c_str(), m.length());
int si = 0;
int mi = 0;
//计算next数组
//最长相同前缀后缀长度值右移一位,然后初值赋为 - 1
if (strlen(ms) == 0){
return -1;
}
int next[10];
next[0] = -1;
next[1] = 0;
int pos = 2; //从下标为2开始计算
int cn = 0; //最大值计数
//在没有遍历完模式串的情况下
while (pos < strlen(ms)){
//比较两头的字符是否相同
if (ms[pos - 1] == ms[cn]){
next[pos++] = ++cn;
} //不相同的话如果
else if (cn > 0){
cn = next[cn];
}
else{ //cn<=0 置为0
next[pos++] = 0;
}
}
////
// 失配时,模式串向右移动的位数为,失配字符所在位置 - 失配字符对应的next 值
while (si < strlen(ss) && mi < strlen(ms)){
if (ss[si] == ms[mi]){ //原始数组中的两个串匹配,同时向右移动
si++;
mi++;
}
else if (next[mi] == -1){ //原始串不匹配,且是模式串第一个元素
si++;
}
else { //模式串匹配了一部分之后,发现不匹配,向右移动原来的next个位数
mi =next[mi];
}
}
return mi == strlen(ms) ? si - mi : -1; //串匹配结束不是因为匹配失败,那么返回匹配成功位置
}
int main(){
string s = "abcabcacab";
// char ss[s.length()];
// std::cout<< s.length()<<std::endl; 5
string match = "acab";
// strncpy(ss,s.c_str(),s.length());
// std::cout<<strlen(ss)<<std::endl;
// std::cout<<sizeof(ss)<<std::endl;
std::cout <<"the result is: "<< getIndexOf(s, match) << std::endl;
return 0;
}