1.关于本文
本文中所有的代码都为实现一个目标,即:
写一个函数:从字符串s中找到字符串a第一次出现的位置,不存在则返回-1
2.方法1:朴素的字符串搜索算法
用一个循环来找出所有有效位移
#include<iostream>
#include<string>
using namespace std;
//函数:找出字符串s中第一次出现字符串a的位置(朴素算法)
int IndexOf_01(string s,string a)
{
bool isMatch;
for(int i = 0; i <= s.length() - a.length(); i++)
{
isMatch = true;
for(int j = 0; j < a.length(); j++)
{
if(s[i + j] != a[j])
{
isMatch = false;
break;
}
}
if(isMatch)
{
return i;
}
}
return -1;
}
int main()
{
string s = "the quick brown fox jumped over the lazy dogs";
cout << s << endl;
cout << "index of \"the\": " << IndexOf_01(s, "the") << endl;
cout << "index of \"quick\": " << IndexOf_01(s, "quick") << endl;
cout << "index of \"dogs\": " << IndexOf_01(s, "dogs") << endl;
cout << "index of \"cats\": " << IndexOf_01(s, "cats") << endl;
return 0;
}
3.方法2
本方法受到了 Rabin-Karp 启发,相当于对原算法做了如下修改
窗口长度:m=a.length(),第一次匹配规则:t=t[0]+t[1]+...+t[t.length()-1],模p=max
对于字符串s的每一个长度为m的子串,如果该子串所有字符的ASCII码和与目标字符串相同,则逐个比对该子串与目标字符串是否相同,否则跳过。若子串与目标字符串相同,则认为匹配,否则继续向后搜索。
#include<iostream>
#include<string>
using namespace std;
//函数:找出字符串s中第一次出现字符串a的位置(受到Rabin-Karp算法启发)
int IndexOf_02(string s,string a)
{
//s的长度应大于a的长度
if(s.length() < a.length())
{
return -1;
}
//计算第一组数字和
int target = 0, current = 0;
for(int i = 0; i < a.length(); i++)
{
target += a[i];
current += s[i];
}
//开始匹配
bool isMatch;
for(int i = 0; i <= s.length() - a.length(); )
{
//如果所有字符的数字和相同,则进一步比较
if(current == target)
{
isMatch = true;
for(int j = 0; j < a.length(); j++)
{
if(s[i + j] != a[j])
{
isMatch = false;
break;
}
}
if(isMatch)
{
return i;
}
}
//计算下一组字符的数字和
current -= s[i];
current += s[i++ + a.length()];
}
return -1;
}
int main()
{
string s = "the quick brown fox jumped over the lazy dogs";
cout << s << endl;
cout << "index of \"the\": " << IndexOf_02(s, "the") << endl;
cout << "index of \"quick\": " << IndexOf_02(s, "quick") << endl;
cout << "index of \"dogs\": " << IndexOf_02(s, "dogs") << endl;
cout << "index of \"cats\": " << IndexOf_02(s, "cats") << endl;
return 0;
}
4.Knuth-Morris-Pratt(KMP)算法
KMP算法,函数ComputePrefix用于计算辅助数组
#include<iostream>
#include<string>
using namespace std;
//计算前缀
int* ComputePrefix(string a)
{
int *array = new int[a.length() + 1];
int x = 0;
array[0] = 0;
for(int i = 1; i < a.length(); i++)
{
if(a[i] == a[x])
{
array[i] = array[i - 1] + 1;
x++;
}
else
{
array[i] = 0;
x = 0;
}
}
return array;
}
//函数:找出字符串s中第一次出现字符串a的位置(KMP算法)
int IndexOf_KMP(string s, string a)
{
//计算前缀
int *perfix = new int[a.length()];
perfix = ComputePrefix(a);
//判断a在s中第一次出现的位置
int x = 0, y = 0;
while(x < s.length())
{
if(s[x + y] == a[y])
{
y++;
if(y == a.length())
{
return x;
}
}
else
{
if(y == 0)
{
x++;
}
else
{
x += (y - perfix[y - 1]);
}
y = 0;
}
}
return -1;
}
int main()
{
string tests = "ababaabababcabab";
cout << tests << endl;
string testa0 = "ababa";
cout << testa0 << ": " << IndexOf_KMP(tests, testa0) << endl;
string testa1 = "ababc";
cout << testa1 << ": " << IndexOf_KMP(tests, testa1) << endl;
string testa2 = "cabab";
cout << testa2 << ": " << IndexOf_KMP(tests, testa2) << endl;
string testa3 = "aaaaa";
cout << testa3 << ": " << IndexOf_KMP(tests, testa3) << endl;
return 0;
}
来源:oschina
链接:https://my.oschina.net/u/1425762/blog/272355