数据结构实验:串模式匹配

目录

1、实验要求

2、函数实现

        (1)容错处理

        (2)输入主串、子串和匹配起始位置

        (3)朴素的模式匹配算法

        (4)KMP改进算法(Next[ ])   

        (5)KMP改进算法(NextVal[ ])

        (6)修改字符串

3、完整代码


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;
}

        以上代码仅供实验参考,若想自身代码能力有确切的提升,还需要融入自己的推演和思考,感谢观看!

  • 16
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

故梦余生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值