C++经典KMP算法的实现

时间:2021-12-03 19:59:15
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
using namespace std;

bool KMP(const string &s1, const string &s2);

vector<int> findMatchInFrontAndBack(const string &s2);
int partPi(const string &amatch);

int main()
{
    cout << "这个程序能够判断s1内是否包含s2" << endl;
    string s1, s2;
    cout << "请输入字符串1" << endl;
    cin >> s1;
    cout << "请输入字符串2" << endl;
    cin >> s2;

    KMP(s1, s2);

    return 0;
}

bool KMP(const string &s1, const string &s2)
{
    if (s2.size()>s1.size())
    {
        cout << "字符串1里面不包含字符串2" << endl;

        return false;
    }
    else
    {
        vector<int> nodes = findMatchInFrontAndBack(s2);

        int histroySite = 0;

        while (s1.size() - s2.size() >= histroySite)
        {
            int matchNum = 0;

            bool allOverMatch = true;
            for (int i = 0;i<s2.size();++i)
            {
                if (s1[histroySite + i] != s2[i])
                {
                    allOverMatch = false;

                    if (matchNum == 0)
                    {
                        ++histroySite;
                    }
                    else
                    {
                        histroySite += (matchNum - nodes[i]);
                    }
                    break;
                }
                else
                {
                    ++matchNum;
                }
            }

            if (allOverMatch)
            {
                cout << "s1中包含s2" << endl;

                cout << s1 << endl;

                for (int i = 0;i<histroySite;++i)
                {
                    cout << " ";
                }
                cout << s2 << endl;

                return true;
            }
        }

        cout << "字符串1里面不包含字符串2" << endl;
        return false;
    }
}

vector<int> findMatchInFrontAndBack(const string &s2)
{
    if (s2.size() == 1)
    {
        vector<int> nodeOfMatch = { 0 };
        return nodeOfMatch;
    }
    else
    {
        vector<int> nodeOfMatch(s2.size() - 1, 0);

        auto be = s2.begin();

        auto en = be + 2;

        for (int i = 1;i<s2.size() - 1;++i)
        {
            string amatch;

            amatch.insert(amatch.end(), be, en);

            nodeOfMatch[i] = partPi(amatch);

            ++en;
        }

        nodeOfMatch.push_back(0);

        return nodeOfMatch;
    }
}

int partPi(const string &amatch)
{
    vector<string> frontOfString;
    vector<string> backOfString;

    auto startOne = amatch.begin();
    auto nextOne = startOne + 1;

    for (int i = 0;i<amatch.size() - 1;++i)
    {
        string fs, bs;

        fs.insert(fs.end(), startOne, nextOne);
        bs.insert(bs.end(), nextOne, amatch.end());

        frontOfString.push_back(fs);
        backOfString.push_back(bs);

        ++nextOne;
    }

    sort(frontOfString.begin(), frontOfString.end());
    sort(backOfString.begin(), backOfString.end());

    int highestNum = 0;

    while (frontOfString.size() != 0 && backOfString.size() != 0)
    {
        auto s1 = frontOfString.begin();
        auto s2 = backOfString.begin();

        if (*s1 == *s2)
        {
            if (s1->size()>highestNum)
            {
                highestNum = s1->size();
            }

            frontOfString.erase(s1);
            backOfString.erase(s2);
        }
        else if (*s1<*s2)
        {
            frontOfString.erase(s1);
        }
        else
        {
            backOfString.erase(s2);
        }
    }

    return highestNum;
}