模式匹配应用

比较经典的Brute-Force算法与KMP算法的效率的优劣。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>  

#define MAXSIZE 60  

typedef struct
{
    char str[MAXSIZE];
    int length;
}SeqString;  

int B_FIndex(SeqString S,int pos,SeqString T,int *count);
int KMP_Index(SeqString S,int pos,SeqString T,int next[],int *count);
void GetNext(SeqString T,int next[]);
void GetNextVal(SeqString T,int nextval[]);
void PrintArray(SeqString T,int next[],int nextval[],int length);
void StrAssign(SeqString *S,char cstr[]);//串的赋值操作
int StrEmpty(SeqString S);//判断串是否为空
int StrLength(SeqString S);//求串的长度操作
void StrCopy(SeqString *T,SeqString S);//串的复制操作
int StrCompare(SeqString S,SeqString T);//串的比较操作
int StrInsert(SeqString *S,int pos,SeqString T);//串的插入操作
int StrDelete(SeqString *S,int pos,int len);//串的删除操作
int StrConcat(SeqString *T,SeqString S);//串的连接操作
int SubString(SeqString *Sub,SeqString S,int poos,int len);//截取子串操作
int StrReplace(SeqString *S,SeqString T,SeqString V);//串的替换操作
int StrIndex(SeqString S,int pos,SeqString T);//串的定位操作
void StrClear(SeqString *S);//清空串操作
void StrPrint(SeqString S);//串的输出声明  

#include "string.h"
/*经典的模式匹配算法Brute-Force*/
/*假设串采用顺序存储方式存储,则Brute-Force匹配算法如下*/  

int B_FIndex(SeqString S,int pos,SeqString T,int *count)
/*在主串S中的第pos个位置开始查找子串T,如果找到,返回子串在主串中的位置;否则返回-1*/
{
    int i,j;
    i = pos-1;
    j = 0;
    *count = 0;
    while(i < S.length && j < T.length)
    {
        if(S.str[i] == T.str[j])
            /*如果串S和串T中对应的位置的字符相等,则继续比较下一个字符*/
        {
            i++;
            j++;
        }
        else
            /*如果当前对应位置的字符不相等,则从串S的下一个字符开始,从T的第0个字符开始比较*/
        {
            i = i-j+1;
            j = 0;
        }
        (*count)++;
    }
    if(j >= T.length)
        /*如果在串S中找到串T,则返回子串T在主串S中的位置*/
    {
        return i-j+1;
    }
    else
    {
        return -1;
    }
}  

/*KMP算法*/
/*KMP算法思想*/
/*利用模式串T的next函数值求T在主串S中的第pos个字符之间的位置的KMP算法描述如下:*/  

int KMP_Index(SeqString S,int pos,SeqString T,int next[],int *count)
{
    int i,j;
    i = pos-1;
    j = 0;
    *count = 0;
    while(i < S.length && j < T.length)
    {
        if(-1 == j || S.str[i] == T.str[j])
            /*如果j=-1或当前字符相等,则继续比较后面的字符*/
        {
            i++;
            j++;
        }
        else/*如果当前字符不相等,则将模式串向右移动*/
        {
            j = next[j];/*数组next保存next函数值*/
        }
        (*count)++;
    }
    if(j >= T.length)/*匹配成功,则返回子串T在主串S中的位置,否则返回-1*/
    {
        return i-T.length+1;
    }
    else
    {
        return -1;
    }
}  

/*求next函数值*/
/*算法描述如下*/
void GetNext(SeqString T,int next[])
{
    int j,k;
    j = 0;
    k = -1;
    next[0] = -1;
    while(j < T.length)
    {
        if(-1 == k || T.str[j] == T.str[k])
        {
            j++;
            k++;
            next[j] = k;
        }
        else
        {
            k = next[k];
        }
    }
}  

/*改进算法如下*/
void GetNextVal(SeqString T,int nextval[])
{
    int j,k;
    j = 0;
    k = -1;
    nextval[0] = -1;
    while(j < T.length)
    {
        if(-1 == k || T.str[j] == T.str[k])
        {
            j++;
            k++;
            if(T.str[j] != T.str[k])
            {
                nextval[j] = k;
            }
            else
            {
                nextval[j] = nextval[k];
            }
        }
        else
        {
            k = nextval[k];
        }
    }
}  

void PrintArray(SeqString T,int next[],int nextval[],int length)
{
    int j;
    printf("j:\t\t");
    for(j = 0;j < length;j++)
    {
        printf("%3d",j);
    }
    printf("\n");
    printf("模式串:\t");
    for(j = 0;j < length;j++)
    {
        printf("%3c",T.str[j]);
    }
    printf("\n");
    printf("next[j]:\t");
    for(j = 0;j < length;j++)
    {
        printf("%3d",next[j]);
    }
    printf("\n");
    printf("nextval[j]:\t");
    for(j = 0;j < length;j++)
    {
        printf("%3d",nextval[j]);
    }
    printf("\n");
}
void StrAssign(SeqString *S,char cstr[])//串的赋值操作(将常量cstr中的字符赋值给串S)
{
    int i = 0;
    for(i = 0;cstr[i]!='\0';i++)
    {
        S->str[i] = cstr[i];
    }
    S->length = i;
}
int StrEmpty(SeqString S)//判断串是否为空
{
    if(S.length == 0)
    {
        return 1;
    }
    else
    {
        return 0;
    }
}
int StrLength(SeqString S)//求串的长度操作
{
    return S.length ;
}
void StrCopy(SeqString *T,SeqString S)//串的复制操作(将串S中的每一个字符赋给T)
{
    int i;
    for(i = 0;i < S.length ;i++)
    {
        T->str[i] = S.str[i];
    }
    T->length = S.length ;
}
int StrCompare(SeqString S,SeqString T)//串的比较操作
{
    int i;
    for(i = 0;i < S.length&&i < T.length ;i++)//比较两个串中的字符
    {
        if(S.str[i] != T.str[i])//如果出现字符不同,则返回两个字符的差值
        {
            return (S.str[i]-T.str[i]);
        }
    }
    return (S.length - T.length);//如果比较完毕,返回两个字符串的长度的差值
}
int StrInsert(SeqString *S,int pos,SeqString T)//串的插入操作(在串S的pos个位置插入串T)
{
    int i;
    if(pos < 0 || pos-1 > S->length)
    {
        printf("插入位置不正确\n");
        return 0;
    }
    if(S->length + T.length <= MAXSIZE)//子串完整插入到串中
    {
        //在插入子串T前,将S中的pos后的字符向后移动len个位置
        for(i = S->length+T.length-1;i >= pos+T.length-1;i--)
        {
            S->str[i] = S->str[i-T.length];
        }
        //将串插入到S中
        for(i = 0;i < T.length ;i++)
        {
            S->str[pos+i-1] = T.str[i];
        }
        S->length = S->length +T.length ;
        return 1;
    }
    else if(pos +T.length <= MAXSIZE)//子串完全插入S中,但是S中的字符会被截断
    {
        for(i = MAXSIZE-1;i > T.length +pos-1;i--)
        {
            S->str[i] = S->str[i-T.length];
        }
        for(i = 0;i < T.length ;i++)
        {
            S->str[i+pos-1] = T.str[i];
        }
        S->length = MAXSIZE;
        return 0;
    }
    else//子串T不能完全插入到S中,T将会有字符被舍弃
    {
        for(i = 0;i < MAXSIZE-pos;i++)
        {
            S->str[i+pos-1] = T.str[i];
        }
        S->length = MAXSIZE;
        return 0;
    }
}
int StrDelete(SeqString *S,int pos,int len)//串的删除操作(在串S中删除pos开始的len个字符,然后将后面的字符向前移动)
{
    int i,flag;
    if(pos < 0 || len < 0 || pos+len-1 > S->length)
    {
        printf("删除位置不正确,参数len不合法\n");
        flag = 0;
    }
    else
    {
        for(i = pos+len;i <= S->length-1;i++)
        {
            S->str[i-len] = S->str[i];
        }
        S->length = S->length -len;//修改串S的长度
        flag = 1;
    }
    return flag;
}
int StrConcat(SeqString *T,SeqString S)//串的连接操作(将串S连接在串T的后面)
{
    int i,flag;
    if(T->length +S.length <= MAXSIZE)
    {
        for(i = T->length ;i < T->length +S.length ;i++)
        {
            T->str[i] = S.str[i-T->length];
        }
        T->length = T->length +S.length ;
        flag = 1;
    }
    else if(T->length < MAXSIZE)
    {
        for(i = T->length ;i < MAXSIZE;i++)
        {
            T->str[i] = S.str[i-T->length];
        }
        T->length = MAXSIZE;
        flag = 0;
    }
    return flag;
}
int SubString(SeqString *Sub,SeqString S,int pos,int len)//截取子串操作(截取串S中从第pos个字符开始,长度为len的连续字符,并赋值给Sub)
{
    int i;
    if(pos < 0 || len < 0 || pos+len-1 > S.length)
    {
        printf("参数pos和len不合法\n");
        return 0;
    }
    else
    {
        for(i = 0;i < len;i++)
        {
            Sub->str[i] = S.str[i+pos-1];
        }
        Sub->length = len;
        return 1;
    }
}
int StrIndex(SeqString S,int pos,SeqString T)//串的定位操作(在主串S中的第pos个位置开始查找子串T,如果主串S中存在与串T值相等的子串,返回子串在主串第pos个字符后第一次出现的位置)
{
    int i,j;
    if(StrEmpty(T))
    {
        return 0;
    }
    i = pos;
    j = 0;
    while(i < S.length && j < T.length)
    {
        if(S.str[i] == T.str[j])
        {
            i++;
            j++;
        }
        else//如果当前对应位置的字符不相等,则从串S的下一个字符开始,从T的第0个字符开始比较
        {
            i = i-j+1;
            j = 0;
        }
    }
    if(j >= T.length)//如果在串S中找到串T,则返回子串T在主串S中的位置
    {
        return i-j+1;
    }
    else
    {
        return -1;
    }
}
int StrReplace(SeqString *S,SeqString T,SeqString V)//串的替换操作(如果串S中存在子串T,则用V替换串S中的所有子串T)
{
    int flag;
    int i = 0;
    if(StrEmpty(T))
    {
        return 0;
    }
    while(i)
    {
        i = StrIndex(*S,i,T);//利用串的定位操作在串S中查找T的位置
        if(i)
        {
            StrDelete(S,i,StrLength(T));//如果找到子串T,则将S中的串T删除
            flag = StrInsert(S,i,V);//将V插入
            if(!flag)
            {
                return 0;
            }
            i += StrLength(V);
        }
    }
    return 1;
}
void StrClear(SeqString *S)//清空串操作
{
    S->length = 0;
}
void StrPrint(SeqString S)//串的输出声明
{
    int i;
    for(i = 0;i < S.length ;i++)
    {
        printf("%c",S.str[i]);
    }
    printf("\n");
}  

#include "string.h"  

int main(void)
{
    SeqString S,T;
    int count1 = 0;
    int count2 = 0;
    int count3 = 0;
    int find;
    int next[40];
    int nextval[40];
    StrAssign(&S,"abaababaddecab");
    StrAssign(&T,"abad");
    GetNext(T,next);
    GetNextVal(T,nextval);
    printf("模式串T的next和改进后的next的值:\n");
    PrintArray(T,next,nextval,StrLength(T));
    find = B_FIndex(S,1,T,&count1);
    if(find > 0)
    {
        printf("Brute-Force算法的比较次数为:%2d\n",count1);
    }
    find = KMP_Index(S,1,T,next,&count2);
    if(find > 0)
    {
        printf("利用next的KMP算法的比较次数为:%2d\n",count2);
    }
    find = KMP_Index(S,1,T,nextval,&count3);
    if(find > 0)
    {
        printf("利用nextval的KMP算法的比较次数为:%2d\n",count3);
    }
    StrAssign(&S,"cbccccbcacbccbacbccbcbcbc");
    StrAssign(&T,"cbccbcbc");
    GetNext(T,next);
    GetNextVal(T,nextval);
    printf("模式串T的next和改进后的next的值:\n");
    PrintArray(T,next,nextval,StrLength(T));
    find = B_FIndex(S,1,T,&count1);
    if(find > 0)
    {
        printf("Brute-Force算法的比较次数为:%2d\n",count1);
    }
    find = KMP_Index(S,1,T,next,&count2);
    if(find > 0)
    {
        printf("利用next的KMP算法的比较次数为:%2d\n",count2);
    }
    find = KMP_Index(S,1,T,nextval,&count3);
    if(find > 0)
    {
        printf("利用nextval的KMP算法的比较次数为:%2d\n",count3);
    }
    return 0;
}  

运行结果如下:

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-18 02:47:51

模式匹配应用的相关文章

字符串的模式匹配中的算法

字符串的模式匹配是一个比较经典的问题:假设有一个字符串S,称其为主串,然后还有一个字符串T,称其为子串. 现在要做的是,从主串S当中查找子串T的位置,如果存在返回位置值,如果不存在返回-1.另外主串又称为目标串, 子串称为模式串. 暴力匹配算法 这是一个经典的串匹配问题,涉及的算法也比较多,先讨论第一种简单的暴力算法,思路如下 将主串S的第pos个字符 与 子串T的第一个字符比较, 若相同,继续比较子串和主串后面的字符. 若不相同,那么从主串S的第(pos + 1)个字符开始继续向后匹配,直到匹

LeetCode:Word Pattern - 字符串模式匹配

1.题目名称 Word Pattern(字符串模式匹配) 2.题目地址 https://leetcode.com/problems/word-pattern/ 3.题目内容 英文:Given a pattern and a string str, find if str follows the same pattern. 中文:给出一组模式(pattern)和一个字符串(str),查看字符串是否与模式匹配 例如: pattern = "abba",str = "dog cat

Scala入门到精通——第十五节 Case Class与模式匹配(二)

本节主要内容 模式匹配的类型 for控制结构中的模式匹配 option类型模式匹配 1. 模式的类型 1 常量模式 object ConstantPattern{ def main(args: Array[String]): Unit = { //注意,下面定义的是一个函数 //函数的返回值利用的是模式匹配后的结果作为其返回值 //还需要注意的是函数定义在main方法中 //也即scala语言可以在一个函数中定义另外一个函数 def patternShow(x:Any)=x match { ca

串模式匹配之BF和KMP算法

本文简要谈一下串的模式匹配.主要阐述BF算法和KMP算法.力求讲的清楚又简洁. 一 BF算法 核心思想是:对于主串s和模式串t,长度令为len1,len2,   依次遍历主串s,即第一次从位置0开始len2个字符是否与t对应的字符相等,如果完全相等,匹配成功:否则,从下个位置1开始,再次比较从1开始len2个字符是否与t对应的字符相等.... BF算法思路清晰简单,但是每次匹配不成功时都要回溯. 下面直接贴代码: int BF_Match(char *s, char *t) { int i=0,

字符串模式匹配KMP算法中的next数组算法及C++实现

一.问题描述: 对于两个字符串S.T,找到T在S中第一次出现的起始位置,若T未在S中出现,则返回-1. 二.输入描述: 两个字符串S.T. 三.输出描述: 字符串T在S中第一次出现的起始位置,若未出现,则返回-1. 四.输入例子: ababaababcbababc 五.输出例子: 5 六.KMP算法解析: KMP算法分为两步,第一步是计算next数组,第二步是根据next数组通过较节省的方式回溯来比较两个字符串. 网络上不同文章关于next数组的角标含义略有差别,这里取参考文献中王红梅<数据结构

字符串模式匹配sunday算法

文字部分转自:http://www.cnblogs.com/mr-ghostaqi/p/4285868.html 代码是我自己写的 今天在做LeetCode的时候,碰到一个写字符串匹配的题目: https://oj.leetcode.com/problems/implement-strstr/ 我一看就懵了,字符串模式匹配我记得当时在上数据结构的时候,书上只写了BF和KMP算法,老师说考试“只可能会考BF”,KMP不要求掌握. 然后出于一颗探求的心,我还是看了一下KMP,这算法好难理解,于是就没

第30讲:模式匹配高级实战:嵌套的Case class

如果一个case class 其构造函数的参数又是另一个case class,那么我们如果使用模式匹配呢? 请看下面的例子 package com.dt.scala.pattern_match abstract class Item case class Book(Description: String,Price: Double) extends Item case class Bundle(Description: String,Price: Double,item: Item*) exte

串的模式匹配

在串的各种操作中,串的模式匹配是经常用到的一个算法.串的模式匹配也称为子串的定位操作,即查找子串在主串中出现的位置. 1.经典的模式匹配算法Brute-Force. 2.KMP算法. #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAXSIZE 60 typedef struct { char ch[MAXSIZE]; int length; }SeqString; #include

KMP模式匹配

在开发中经常遇到需要查看一个字符串t是否在字符串s中存在,并找到其第一次出现的位置,也就是在字符串s中查找子串t,我们平常都是怎么实现那?我们最起码有三个方法可以用,CString和string中的find函数,以及string.h中的strstr函数,用起来既简单又快捷,CString是MFC中的东西,string是C++标准库的东西,strstr是C中string.h中的东西,貌似我们没必要非要自己实现定位查找功能--但是如果我偏要想自己实现那?我们能不能模仿MFC中的CString或者C+

字符串模式匹配之KMP算法图解与 next 数组原理和实现方案

之前说到,朴素的匹配,每趟比较,都要回溯主串的指针,费事.则 KMP 就是对朴素匹配的一种改进.正好复习一下. KMP 算法其改进思想在于: 每当一趟匹配过程中出现字符比较不相等时,不需要回溯主串的 i指针,而是利用已经得到的“部分匹配”的结果将模式子串向右“滑动”尽可能远的一段距离后,继续进行比较.如果 ok,那么主串的指示指针不回溯!算法的时间复杂度只和子串有关!很好. KMP算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的,很自然的,需要一个函数来存储匹