算法原理: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()); // //for (int i = 0; i < m.length(); i++){ // std::cout << ms[i]; //} //std::cout << std::endl; //// 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; } } //std::cout <<"strlen(ms) :" << strlen(ms)<<std::endl; //// //for (int i = 0; i < strlen(ms); i++){ // cout << next[i]; //} //std::cout << std::endl; //// // 失配时,模式串向右移动的位数为,失配字符所在位置 - 失配字符对应的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; }