目录
1、实验要求
实现功能:朴素的模式匹配算法(BF算法)、KMP改进算法(Next[ ])、KMP改进算法(NextVal[ ])。
主控菜单:
1.输入主串、子串和匹配起始位置
2.朴素的模式匹配算法
3.KMP改进算法(Next[ ])
4.KMP改进算法(NextVal[ ])
0.退出管理系统
实现菜单2的功能:朴素的模式匹配算法,输出各趟匹配详细过程,然后输出匹配总趟数、单个字符比较次数、匹配成功时的位置序号或者匹配失败提示信息。
实现菜单3的功能:KMP改进算法(Next[ ]),输出Next[ ]各元素的数值、各趟匹配详细过程,然后输出匹配总趟数、单个字符比较次数、匹配成功时的位置序号或者匹配失败提示信息。
实现菜单4的功能:KMP改进算法(NextVal[ ]),输出NextVal[ ]的各元素的数值、各趟匹配详细过程,然后输出匹配总趟数、单个字符比较次数、匹配成功时的位置序号或者匹配失败提示信息。
此外还要实现容错处理,检测任何不合规的输入,并给出必要提示。并优化交互界面,让非专业者(陌生人)也能顺利完成运算。
2、函数实现
(1)容错处理
由于存在容错处理防止程序崩溃,所以需要将输入过程封装成一个函数,如果输入的为正常数字则继续执行功能,如果输入的为乱码或字符,则需重新输入。创建好容错处理函数后,后面的输入只需“int a = Judge()”即可。
int Judge() {
int j;
while (true) {
if (!scanf_s("%d", &j)) {
cout << "非法字符!请重新输入:";
while (getchar() != '\n');
}
else if (getchar() != '\n') {
cout << "非法字符!请重新输入:";
while (getchar() != '\n');
}
else if (j < 0) cout << "非法字符!请重新输入:";
else break;
}
return j;
}
(2)输入主串、子串和匹配起始位置
void Action(string& dad, string& son, int& begin) {
cout << "请输入主串:";
cin >> dad;
cout << "请输入子串:";
cin >> son;
while (son.size() > dad.size()) {
cout << "子串长度不能大于主串长度,请重新输入:";
cin >> son;
}
cout << "请输入匹配起始位置(从1开始):";
begin = Judge();//容错处理
while (begin > dad.size()) {
cout << "主串长度为:" << dad.size() << ",起始位置越界,请重新输入:";
begin = Judge();
}
}
(3)朴素的模式匹配算法
void SimpleMatch(string& dad, string& son, int begin) {
int cnt = 0, now_d = begin - 1, now_s = 0;
int book[100] = { 0 };
cout << "匹配具体过程如下:" << endl;
while (now_d < dad.size() && now_s < son.size()) {//通过循环输出每趟匹配详细过程
if (now_s == 0 && now_d < dad.size()) {
cout << dad << endl;
for (int i = 0; i < now_d; i++)cout << " ";
}
if (dad[now_d] == son[now_s]) {
book[now_s]++;
now_d++;
now_s++;
}
else {
for (int i = 0; i <= now_s; i++) cout << son[i];
cout << endl;
cnt++;
book[now_s]++;
now_d = now_d - now_s + 1;
now_s = 0;
}
}
if (now_s == son.size()) {
cout << son << endl;
cout << "匹配成功!" << endl;
cout << "匹配总趟数为:" << cnt + 1 << endl;
cout << "匹配成功时的位置序号:" << now_d - now_s + 1 << endl;
cout << "子串各个字符比较次数为:";
for (int i = 0; i < son.size(); i++) cout << book[i] << " ";
cout << endl;
}
else {
cout << son << endl;
cout << "匹配失败!" << endl;
cout << "匹配总趟数为:" << cnt << endl;
cout << "子串各个字符比较次数为:";
for (int i = 0; i < son.size(); i++) cout << book[i] << " ";
cout << endl;
}
}
(4)KMP改进算法(Next[ ])
//得到next数组
void GetNext(string son, int next[]) {
next[0] = -1;
next[1] = 0;
int i = 1, j = 0;
while (i <= son.size()) {
if (j == 0 || son[i - 1] == son[j - 1]) next[++i] = ++j;
else j = next[j];
}
}
//KMP改进算法(Next[ ])
void KMP_next(string& dad, string& son, int begin, int next[]) {
int cnt = 0, now_d = begin - 1, now_s = 0;
int book[100] = { 0 };
cout << "匹配具体过程如下:" << endl;
int mark = 0;
while (now_d < dad.size() && now_s < son.size() || now_s == -1) {//通过循环输出每趟匹配详细过程
if (mark == 0 && now_d < dad.size()-1) {
cout << dad << endl;
for (int i = 0; i < now_d - now_s; ++i) cout << " ";
}
if (now_s == -1 || dad[now_d] == son[now_s]) {
mark = 1;
if(now_s!=-1)book[now_s]++;
now_s++;
now_d++;
}
else {
for (int i = 0; i <= now_s; ++i) cout << son[i];
cout << endl;
mark = 0;
book[now_s]++;
now_s = next[now_s];
cnt++;
}
}
if (now_s == son.size()) {
cout << son << endl;
cout << "匹配成功!" << endl;
cout << "匹配总趟数为:" << cnt + 1 << endl;
cout << "匹配成功时的位置序号:" << now_d - now_s + 1 << endl;
cout << "子串各个字符比较次数为:";
for (int i = 0; i < son.size(); i++) cout << book[i] << " ";
cout << endl;
cout << "next数组如下所示:" << endl;
for (int i = 1; i <= son.size(); ++i) cout << next[i] << " ";
}
else {
cout << son << endl;
cout << "匹配失败!" << endl;
cout << "匹配总趟数为:" << cnt << endl;
cout << "子串各个字符比较次数为:";
for (int i = 0; i < son.size(); i++) cout << book[i] << " ";
cout << endl;
cout << "next数组如下所示:" << endl;
for (int i = 1; i <= son.size(); ++i) cout << next[i] << " ";
}
cout << endl;
}
(5)KMP改进算法(NextVal[ ])
//得到nextval数组
void GetNextval(string son, int next[], int nextval[]) {
GetNext(son, next);
GetNext(son, nextval);
for (int j = 2; j <= son.size(); ++j) {
if (son[j - 1] == son[next[j] - 1]) {
nextval[j] = nextval[nextval[j]];
}
}
}
//KMP改进算法(Nextval[ ])
void KMP_nextval(string& dad, string& son, int begin, int nextval[]) {
int cnt = 0, now_d = begin - 1, now_s = 0;
int book[100] = { 0 };
cout << "匹配具体过程如下:" << endl;
int mark = 0;
while (now_d < dad.size() && now_s < son.size() || now_s == -1) {//通过循环输出每趟匹配详细过程
if (mark == 0 && now_d < dad.size()-1) {
cout << dad << endl;
for (int i = 0; i < now_d - now_s; ++i) cout << " ";
}
if (now_s == -1 || dad[now_d] == son[now_s]) {
mark = 1;
if (now_s != -1)book[now_s]++;
now_s++;
now_d++;
}
else {
for (int i = 0; i <= now_s; ++i) cout << son[i];
cout << endl;
mark = 0;
book[now_s]++;
now_s = nextval[now_s];
cnt++;
}
}
if (now_s == son.size()) {
cout << son << endl;
cout << "匹配成功!" << endl;
cout << "匹配总趟数为:" << cnt + 1 << endl;
cout << "匹配成功时的位置序号:" << now_d - now_s + 1 << endl;
cout << "子串各个字符比较次数为:";
for (int i = 0; i < son.size(); i++) cout << book[i] << " ";
cout << endl;
cout << "nextval数组如下所示:" << endl;
for (int i = 1; i <= son.size(); ++i) cout << nextval[i] << " ";
}
else {
cout << son << endl;
cout << "匹配失败!" << endl;
cout << "匹配总趟数为:" << cnt << endl;
cout << "子串各个字符比较次数为:";
for (int i = 0; i < son.size(); i++) cout << book[i] << " ";
cout << endl;
cout << "nextval数组如下所示:" << endl;
for (int i = 1; i <= son.size(); ++i) cout << nextval[i] << " ";
}
cout << endl;
}
(6)修改字符串
//修改主串
void DadChange(string& str, int len, int& begin) {
cout << "将主串修改为:";
cin >> str;
while (str.size() < len) {
cout << "主串长度不能小于子串,请重新输入主串:" << endl;
cin >> str;
}
cout << "请输入匹配起始位置(从1开始):";
begin = Judge();
while (begin > str.size()) {
cout << "主串长度为:" << str.size() << ",起始位置越界,请重新输入:";
begin = Judge();
}
}
//修改子串
void SonChange(string& str, int len) {
cout << "将子串修改为:";
cin >> str;
while (str.size() > len) {
cout << "子串长度不能大于主串,请重新输入子串:" << endl;
cin >> str;
}
}
3、完整代码
前面函数功能已经全部实现,现在利用while和switch实现功能菜单循环,完整代码附上:
#include<iostream>
#include<string>
using namespace std;
int Judge();//容错函数
void Action(string& dad, string& son, int& begin);//输入主串、子串和匹配起始位置
void SimpleMatch(string& dad, string& son, int begin);//朴素的模式匹配算法
void KMP_next(string& dad, string& son, int begin, int next[]);//KMP改进算法(Next[ ])
void KMP_nextval(string& dad, string& son, int begin, int nextval[]);//KMP改进算法(Nextval[ ])
void GetNext(string son, int next[]);//得到next数组
void GetNextval(string son, int next[], int nextval[]);//得到nextval数组
void DadChange(string& str, int len, int& begin);//修改主串
void SonChange(string& str, int len);//修改子串
int main() {
string dad, son;//主串和子串
int begin = 0, n;//起始位置和功能序号
//进行功能选项
cout << "==================================" << endl;
cout << "||请输入功能编号,运行相应功能\t||" << endl;
cout << "||1.输入主串、子串和匹配起始位置||" << endl;
cout << "||2.朴素的模式匹配算法\t\t||" << endl;
cout << "||3.KMP改进算法(Next[ ])\t||" << endl;
cout << "||4.KMP改进算法(NextVal[ ])\t||" << endl;
cout << "||5.修改字符串\t\t\t||" << endl;
cout << "||0.退出管理系统\t\t||" << endl;
cout << "==================================" << endl;
while (true) {
n = Judge();
if (n < 1 || n>5) break;
switch (n) {
case 1:
Action(dad, son, begin);
break;
case 2:
if (dad.size() == 0 || son.size() == 0)cout << "请先输入主串和子串" << endl;
else SimpleMatch(dad, son, begin);
break;
case 3:
if (dad.size() == 0 || son.size() == 0)cout << "请先输入主串和子串" << endl;
else {
int next[100];
GetNext(son, next);
KMP_next(dad, son, begin, next);
}
break;
case 4:
if (dad.size() == 0 || son.size() == 0)cout << "请先输入主串和子串" << endl;
else {
int next[100];
int nextval[100];
GetNext(son, next);
GetNextval(son, next, nextval);
KMP_nextval(dad, son, begin, nextval);
}
break;
case 5:
if (dad.size() == 0 || son.size() == 0)cout << "请先输入主串和子串" << endl;
else {
int change;
cout << "请选择修改主串或子串:(1.修改主串 2.修改子串)";
begin:change = Judge();
if (change == 1) DadChange(dad,son.size(),begin);
else if (change == 2) SonChange(son,dad.size());
else {
cout << "输入有误,请重新输入:";
goto begin;
}
}
break;
default:
break;
}
cout << "==================================" << endl;
cout << "||请输入功能编号,运行相应功能\t||" << endl;
cout << "||1.输入主串、子串和匹配起始位置||" << endl;
cout << "||2.朴素的模式匹配算法\t\t||" << endl;
cout << "||3.KMP改进算法(Next[ ])\t||" << endl;
cout << "||4.KMP改进算法(NextVal[ ])\t||" << endl;
cout << "||5.修改字符串\t\t\t||" << endl;
cout << "||0.退出管理系统\t\t||" << endl;
cout << "==================================" << endl;
}
return 0;
}
//修改主串
void DadChange(string& str, int len, int& begin) {
cout << "将主串修改为:";
cin >> str;
while (str.size() < len) {
cout << "主串长度不能小于子串,请重新输入主串:" << endl;
cin >> str;
}
cout << "请输入匹配起始位置(从1开始):";
begin = Judge();
while (begin > str.size()) {
cout << "主串长度为:" << str.size() << ",起始位置越界,请重新输入:";
begin = Judge();
}
}
//修改子串
void SonChange(string& str, int len) {
cout << "将子串修改为:";
cin >> str;
while (str.size() > len) {
cout << "子串长度不能大于主串,请重新输入子串:" << endl;
cin >> str;
}
}
//容错处理函数
int Judge() {
int j;
while (true) {
if (!scanf_s("%d", &j)) {
cout << "非法字符!请重新输入:";
while (getchar() != '\n');
}
else if (getchar() != '\n') {
cout << "非法字符!请重新输入:";
while (getchar() != '\n');
}
else if (j < 0) cout << "非法字符!请重新输入:";
else break;
}
return j;
}
//得到next数组
void GetNext(string son, int next[]) {
next[0] = -1;
next[1] = 0;
int i = 1, j = 0;
while (i <= son.size()) {
if (j == 0 || son[i - 1] == son[j - 1]) next[++i] = ++j;
else j = next[j];
}
}
//得到nextval数组
void GetNextval(string son, int next[], int nextval[]) {
GetNext(son, next);
GetNext(son, nextval);
for (int j = 2; j <= son.size(); ++j) {
if (son[j - 1] == son[next[j] - 1]) {
nextval[j] = nextval[nextval[j]];
}
}
}
//输入主串、子串和匹配起始位置
void Action(string& dad, string& son, int& begin) {
cout << "请输入主串:";
cin >> dad;
cout << "请输入子串:";
cin >> son;
while (son.size() > dad.size()) {
cout << "子串长度不能大于主串长度,请重新输入:";
cin >> son;
}
cout << "请输入匹配起始位置(从1开始):";
begin = Judge();
while (begin > dad.size()) {
cout << "主串长度为:" << dad.size() << ",起始位置越界,请重新输入:";
begin = Judge();
}
}
//朴素的模式匹配算法
void SimpleMatch(string& dad, string& son, int begin) {
int cnt = 0, now_d = begin - 1, now_s = 0;
int book[100] = { 0 };
cout << "匹配具体过程如下:" << endl;
while (now_d < dad.size() && now_s < son.size()) {//通过循环输出每趟匹配详细过程
if (now_s == 0 && now_d < dad.size()) {
cout << dad << endl;
for (int i = 0; i < now_d; i++)cout << " ";
}
if (dad[now_d] == son[now_s]) {
book[now_s]++;
now_d++;
now_s++;
}
else {
for (int i = 0; i <= now_s; i++) cout << son[i];
cout << endl;
cnt++;
book[now_s]++;
now_d = now_d - now_s + 1;
now_s = 0;
}
}
if (now_s == son.size()) {
cout << son << endl;
cout << "匹配成功!" << endl;
cout << "匹配总趟数为:" << cnt + 1 << endl;
cout << "匹配成功时的位置序号:" << now_d - now_s + 1 << endl;
cout << "子串各个字符比较次数为:";
for (int i = 0; i < son.size(); i++) cout << book[i] << " ";
cout << endl;
}
else {
cout << son << endl;
cout << "匹配失败!" << endl;
cout << "匹配总趟数为:" << cnt << endl;
cout << "子串各个字符比较次数为:";
for (int i = 0; i < son.size(); i++) cout << book[i] << " ";
cout << endl;
}
}
//KMP改进算法(Next[ ])
void KMP_next(string& dad, string& son, int begin, int next[]) {
int cnt = 0, now_d = begin - 1, now_s = 0;
int book[100] = { 0 };
cout << "匹配具体过程如下:" << endl;
int mark = 0;
while (now_d < dad.size() && now_s < son.size() || now_s == -1) {//通过循环输出每趟匹配详细过程
if (mark == 0 && now_d < dad.size()-1) {
cout << dad << endl;
for (int i = 0; i < now_d - now_s; ++i) cout << " ";
}
if (now_s == -1 || dad[now_d] == son[now_s]) {
mark = 1;
if(now_s!=-1)book[now_s]++;
now_s++;
now_d++;
}
else {
for (int i = 0; i <= now_s; ++i) cout << son[i];
cout << endl;
mark = 0;
book[now_s]++;
now_s = next[now_s];
cnt++;
}
}
if (now_s == son.size()) {
cout << son << endl;
cout << "匹配成功!" << endl;
cout << "匹配总趟数为:" << cnt + 1 << endl;
cout << "匹配成功时的位置序号:" << now_d - now_s + 1 << endl;
cout << "子串各个字符比较次数为:";
for (int i = 0; i < son.size(); i++) cout << book[i] << " ";
cout << endl;
cout << "next数组如下所示:" << endl;
for (int i = 1; i <= son.size(); ++i) cout << next[i] << " ";
}
else {
cout << son << endl;
cout << "匹配失败!" << endl;
cout << "匹配总趟数为:" << cnt << endl;
cout << "子串各个字符比较次数为:";
for (int i = 0; i < son.size(); i++) cout << book[i] << " ";
cout << endl;
cout << "next数组如下所示:" << endl;
for (int i = 1; i <= son.size(); ++i) cout << next[i] << " ";
}
cout << endl;
}
//KMP改进算法(Nextval[ ])
void KMP_nextval(string& dad, string& son, int begin, int nextval[]) {
int cnt = 0, now_d = begin - 1, now_s = 0;
int book[100] = { 0 };
cout << "匹配具体过程如下:" << endl;
int mark = 0;
while (now_d < dad.size() && now_s < son.size() || now_s == -1) {//通过循环输出每趟匹配详细过程
if (mark == 0 && now_d < dad.size()-1) {
cout << dad << endl;
for (int i = 0; i < now_d - now_s; ++i) cout << " ";
}
if (now_s == -1 || dad[now_d] == son[now_s]) {
mark = 1;
if (now_s != -1)book[now_s]++;
now_s++;
now_d++;
}
else {
for (int i = 0; i <= now_s; ++i) cout << son[i];
cout << endl;
mark = 0;
book[now_s]++;
now_s = nextval[now_s];
cnt++;
}
}
if (now_s == son.size()) {
cout << son << endl;
cout << "匹配成功!" << endl;
cout << "匹配总趟数为:" << cnt + 1 << endl;
cout << "匹配成功时的位置序号:" << now_d - now_s + 1 << endl;
cout << "子串各个字符比较次数为:";
for (int i = 0; i < son.size(); i++) cout << book[i] << " ";
cout << endl;
cout << "nextval数组如下所示:" << endl;
for (int i = 1; i <= son.size(); ++i) cout << nextval[i] << " ";
}
else {
cout << son << endl;
cout << "匹配失败!" << endl;
cout << "匹配总趟数为:" << cnt << endl;
cout << "子串各个字符比较次数为:";
for (int i = 0; i < son.size(); i++) cout << book[i] << " ";
cout << endl;
cout << "nextval数组如下所示:" << endl;
for (int i = 1; i <= son.size(); ++i) cout << nextval[i] << " ";
}
cout << endl;
}
以上代码仅供实验参考,若想自身代码能力有确切的提升,还需要融入自己的推演和思考,感谢观看!