字符串匹配算法

字符串匹配算法之有限自动机

  • 代码分为两个个部分:
    建立状态转移函数

     Transition函数:一个vector<map<char,int> >transition_map(m+1);
     	建立从数字到字符的对应关系,遍历P中每一个字符的每一种可能并找到K值;
     Matching_Prefix_Suffix:匹配前后缀://检验P[0...k-1]==P[q-k+1...q]是否匹配
    

匹配字符:没什么,就是匹配得K与m相等则匹配成功;
在这里插入图片描述

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<map>
#include<vector>
using namespace std;
bool Matching_Prefix_Suffix(char* P,int k,int q,char c);
vector<map<char,int> > Transition( char *P,const char* input_character);//状态转移函数的计算
void Finite_Automaton_Matcher(char* T,char* P,vector<map<char,int> >transition_map);
int main()
{
    const char* input_character="abc";        //输入字母表
    char T[]="abababacaba";                  //文本串
    char P[]="ababaca";                      //模式串
    vector<map<char,int> >transition_map=Transition(P,input_character);//char 为自动机中的字符 int 为转移函数值
    Finite_Automaton_Matcher(T,P,transition_map);
    return 0;
}
void Finite_Automaton_Matcher(char* T,char* P,vector<map<char,int> >transition_map)
{
    int n=strlen(T);                           //文本串长度
    int m=strlen(P);                           //模式串长度
    int q=0;                                   //转移函数的值
    for(int i=0;i<n;i++){                    //对于文本串中的每一个字符
        q=transition_map[q][T[i]];             //迭代 前一个字符的转移函数值
        if(q==m)                                //转移函数的值等于模式串的长度
            printf("Pattern occurs with shift %d\n",i+1-m);   //模式串的有效位移为i-m+1
    }
}
bool Matching_Prefix_Suffix(char* P,int k,int q,char c)
{                               //P为模式串 K为要验证的前缀和后缀的字符串长度
    if(k==0)                    //q为当前自动机主线长度
        return true;              //k=0 空字符串 前缀和后缀肯定相等
    if(k==1){                //只有一个字符串 证明自动机刚好开始创建
        return P[0]==c;      //如果模式串的第一个和其中的c相等 前缀等于后缀
    }
    return P[k-1]==c&&(!strncmp(P,P+q-k+1,k-1));//strncmp函数比较前k-1个数,也就是[0...k-2];匹配则返回0;    
    //检验P[0...k-1]==P[q-k+1...q]
}
vector<map<char,int> > Transition( char *P,const char* input_character)//计算转移函数的值
{
    int m=strlen(P);                //模式串的长度
    int j=0,k;
    printf("The main length of Finite_Automaton_Matcher is %d\n",m);
    vector<map<char,int> >transition_map(m+1);         //创建一个vector 一共有m+1个数据
    for(int i=0;i<m;i++){                   //对于模式串的长度
        j=0;
        while(input_character[j]!='\0'){      //对于输入串的每一种可能字符
            k= min(m,i+1);               //因为对于长度为i的字符串 它的转移函数最大值为i//数组下标从0开始 再加上后面k一来就减1  所以为i+2
            //找到一个最大值k使得模式串的P[0...k]==P[...n-1]
            while(!Matching_Prefix_Suffix(P,k,i,input_character[j])){
                k=k-1;
            }
            transition_map[i][input_character[j]]=k;
            j++;
        }
    }
    for(int i=0;i<m;i++){
        j=0;
        while(input_character[j]!='\0'){
            printf("<%d,%c>=%d\n",i,input_character[j],transition_map[i][input_character[j]]);
            j++;
        }
    }
    return  transition_map;           //返回一个vector 每一个元素为 map<char,int>
}  

字符串匹配算法之KMP

  • 代码分为两个部分:

     建立求前缀函数get_pai:
     	对j有pai[j]=k;k:P[0 ~ k-1] == P[j-k ~ j-1],也就是前j个数中前缀与后缀匹配的最大长k;
     匹配字符:如果S[i]!=P[j],则j=pai[j];
    
#include <iostream>
#include <string>
#include <vector>
using namespace std;
void cal_next(string &str, vector<int> &next);
vector<int> KMP(string &str1, string &str2, vector<int> &next);
int main(int argc, char const *argv[])
{
    vector<int> vec(20, 0);
    vector<int> vec_test;
    string str1 = "abababacaba";
    string str2 = "ababaca";
    vec_test = KMP(str1, str2, vec);
    int k=vec_test.size();
    for (int i=0;i<k;i++)
        cout<<vec_test[i]<< endl;
    return 0;
}
//部分匹配表
void cal_next(string &str, vector<int> &next)
{
    const int len = str.size();
    next[0] = -1;
    int k = -1;
    int j = 0;
    while (j<len-1)
    {
        if (k==-1||str[j]==str[k])
        {
            ++k;++j;
            next[j]=k;//表示第j个字符有k个匹配(“最大长度值” 整体向右移动一位,然后初始值赋为-1)
        }
        else
            k = next[k];//往前回溯
    }
}
vector<int> KMP(string &str1, string &str2, vector<int> &next)
{
    vector<int> vec;
    cal_next(str2, next);
    int i = 0;//i是str1的下标
    int j = 0;//j是str2的下标
    int str1_size = str1.size();
    int str2_size = str2.size();
    while (i < str1_size && j < str2_size)
    {
        //如果j = -1,或者当前字符匹配成功(即S[i] == P[j]),
        //都令i++,j++. 注意:这里判断顺序不能调换!
        if (j == -1 || str1[i] == str2[j]){++i;++j;}
        else    j = next[j];//当前字符匹配失败,直接从str[j]开始比较,i的位置不变
        if (j == str2_size)//匹配成功
        {
            vec.push_back(i - j);//记录下完全匹配最开始的位置
            j = -1;//重置
        }
    }
    return vec;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值