数据结构 字符串 模式匹配问题 KMP算法

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构 字符串 模式匹配问题 KMP算法相关的知识,希望对你有一定的参考价值。

//头文件定义为:
#include <stdio.h>
//#include <stdlib.h>
#include <string.h>
//#include <malloc.h>

//宏定义:
#define OVERFLOW -2
#define OK 1
#define MAXSTRLEN 255

typedef char SString[MAXSTRLEN+1];

int Index(SString S,SString T,int pos)
//按照普通匹配查找方式查找模式串
int i=pos;
int j=1,k=0;
while(i<=S[0] && j<=T[0])

if(S[i]==T[j])

++i;
++j;

else

i=i-j+2;
j=1;



if(j>T[0])
return i-T[0];
else return 0;
//Index

void get_next(SString T,int next[])
//求KMP算法中的next函数值,并存入数组next[]
int i=1;
next[1]=0;
int j=0;
while(i<T[0])

if(j==0 || T[i-1]==T[j-1])

++i;
++j;

next[i]=j;

else j=next[j];

//next

int get_nextval(SString T,int nextval[])

int i=1;
nextval[1]=0;
int j=0;
while(i<T[0])

if(j==0 || T[i-1]==T[j-1])

++i;
++j;
if(T[i-1]!=T[j-1])
nextval[i]=j;
else
nextval[i]=nextval[j];

else j=nextval[j];

return 0;
//nextval

int Index_KMP(SString S,SString T,int pos,int next[])
//KMP算法的实现过程
int i=pos;
int j=1,k=0;
while(i<=S[0] && j<=T[0])

if(j==0 || S[i]==T[j])

++i;
++j;

else

j=next[j];



if(j>T[0])
return i-T[0];
else return 0;
//Index_KMP

void main()

SString T,S;
int pos;
int k1,k2;
int i,j;
int next[MAXSTRLEN];
int nextval[MAXSTRLEN];
printf("请输入字符串匹配主串:\n");
gets(S);
printf("请输入字符串匹配模式串:\n");
gets(T);

getchar();
printf("您输入的字符串匹配中主串为:\n");
puts(S);

printf("您输入的字符串匹配中模式串为:\n");
puts(T);
getchar();
printf("请您输入起始位置pos:");
scanf("%d",&pos);

printf("\n----------运用普通算法------------\n");
printf("\n");
if(k1=Index(S,T,pos))
printf("匹配成功!\n普通匹配算法得模式串位置:%d\n",k1);
else
printf("没有找到,匹配失败!\n");
printf("\n----------运用KMP算法------------\n");

get_next(T,next);
printf("得到T的next[]序列为:");
for(i=1;i<=strlen(T);i++)
printf("%d",next[i]);

get_nextval(T,nextval);
printf("\n得到T的nextval[]序列为:");
for(i=1;i<=strlen(T);i++)
printf("%d",nextval[i]);
printf("\n");

if(k2=Index_KMP(S,T,pos,next))
printf("匹配成功!\nKMP算法得模式串位置:%d\n",k2);
else
printf("没有找到,匹配失败!");

为什么可以输出NEXT值,但是就是找不到匹配呢?
求纠正啊!!!急啊!!!帮帮忙!!!看看!!!

你的程序本身思路没有错,但错在以下几点:
1.在程序中有字符串S和T,你用S[0]代表字符串的长度,但S是字符串,S[0]是长度吗?
2.在main函数中,你输入的S和T都是用gets(S)或gets(T),那么它们都是以下标0开头的,你应该要进行处理,使它以下标1作为开头(可以这样gets(&S[1]); 然后S[0] = strlen(&S[1]) + '0';在用S[0]作为长度的时候,把它从字符变成数字就行了)。
参考技术A wqewqeqwr3r43wr追问

来混财富值么???童鞋。。。我用追问赏给你。。。。

kmp算法字符串匹配算法

简介

字符串模式匹配是对字符串的基本操作之一,广泛应用于生物信息学、信息检索、拼写检查、语言翻译、数据压缩、网络入侵检测等领域,如何简化其复杂性一直是算法研究中的经典问题。字符串的模式匹配实质上就是寻找模式串P是否在主串T 中,且其出现的位置。我们对字符串匹配的效率的要求越来越高, 应不断地改良模式匹配算法,减少其时间复杂度。

算法说明

设主串(下文中我们称作T)为:a b a c a a b a c a b a c a b a a b b
模式串(下文中我们称作W)为:a b a c a b
用暴力算法匹配字符串过程中,我们会把T[0] 跟 W[0] 匹配,如果相同则匹配下一个字符,直到出现不相同的情况,此时我们会丢弃前面的匹配信息,然后把T[1] 跟 W[0]匹配,循环进行,直到主串结束,或者出现匹配成功的情况。这种丢弃前面的匹配信息的方法,极大地降低了匹配效率。
而在KMP算法中,对于每一个模式串我们会事先计算出模式串的内部匹配信息,在匹配失败时最大的移动模式串,以减少匹配次数。
比如,在简单的一次匹配失败后,我们会想将模式串尽量的右移和主串进行匹配。右移的距离在KMP算法中是如此计算的:在已经匹配的模式串子串中,找出最长的相同的前缀后缀,然后移动使它们重叠。
在第一次匹配过程中
T: a b a c a a b a c a b a c a b a a b b
W: a b a c a b
在T[5]与W[5]出现了不匹配,而T[0]~T[4]是匹配的,其中T[0]~T[4]就是上文中说的已经匹配的模式串子串,移动找出最长的相同的前缀和后缀并使他们重叠:
T: a b a c aa b a c a b a c a b a a b b
W: a b a c a b
然后在从上次匹配失败的地方进行匹配,这样就减少了匹配次数,增加了效率。
然而,如果每次都要计算最长的相同的前缀反而会浪费时间,所以对于模式串来说,我们会提前计算出每个匹配失败的位置应该移动的距离,花费的时间就成了常数时间。比如:
j 0 1 2 3 4 5
W[j] a b a c a b
F(j) 0 0 1 0 1 1
当W[j]与T[j]不匹配的时候,设置j = F(j-1).
朱洪对KMP算法作了修改,他修改了KMP算法中的next函数,即求next函数时不但要求W[1,next(j)-1]=W[j-(next(j)-1),j-1],而且要求W[next(j)]<>W[j],他记修改后的next函数为newnext。显然在模式串字符重复高的情况下,朱洪的KMP算法比KMP算法更加有效。
假设在执行正文中自位置 i 起“返前”的一段与模式的自右至左的匹配检查中,一旦发现不匹配(不管在什么位置),则去执行由W[m]与t[i]+d(x)起始的自右至左的匹配检查,这里x是字符t。它的效果相当于把模式向右滑过d(ti)一段距离。显然,若ti不在模式中出现或仅仅在模式末端出现,则模式向右滑过的最大的一段距离m。图1.1示出了执行BM算法时的各种情况。实线连接发现不匹配以后要进行比较的正文和模式中的字母,虚线连接BM算法在模式向右滑后正文和模式中应对齐的字母,星号表示正文中的一个字母。
public class StringMatching {
    public static void main(String[] args) {
        //暴力匹配算法
        String str1 = "硅硅谷 尚硅谷你尚硅 尚硅谷你尚硅谷你尚硅你好";
        String str2 = "尚硅谷你尚硅你";
        int match = violenceMatch(str1, str2);
       // System.out.println(match);

        String s1= "BBC ABCDAB ABCDABCDABDE";
        String s2 = "ABCDABD";
        String s3 = "ABC";
        int[] next = kmpNext("ABCDABD");//[0,1]
        int res = kMP(s1, s2, next);
        System.out.println(Arrays.toString(next));
        System.out.println(res);

    }


    /*暴力匹配算法*/
    public  static  int violenceMatch(String str1,String str2){
      char[] s1 = str1.toCharArray();
      char[] s2 = str2.toCharArray();
      int i=0;//索引指向s1
      int j = 0;//索引指向s2
        while (i<s1.length&&j<s2.length){//匹配不越界
            if (s1[i] ==s2[j]){//匹配成功
               i++;
               j++;
            }else {//不成功
                i = i -(j-1);
                j=0;
            }
        }
        //判断是否匹配成功
        if (j==s2.length){
            return  i-j;
        }else {
            return -1;
        }
    }

   /*获取到一个字符串的部分匹配值*/
    public static  int[] kmpNext(String dest){
        /*保存部分匹配值*/
        int[] next = new int[dest.length()];
        next[0] = 0;//如果字符串长度为1;部分匹配值是0;
        for (int i = 1 ,j=0; i <dest.length() ; i++) {
            //当不相等时需要从j-1获取新的j
            /*直到发现dest.charAt(i) == dest.charAt(j)退出*/
               while (j>0 &dest.charAt(i) != dest.charAt(j)){
                   j=next[j-1];//kmp算法的基础
               }
        if (dest.charAt(i) == dest.charAt(j)){
            j++;
        }
        next[i] =j;
        }
        return next;
    }

    /*KMP算法查找字符最早出现的位置*/
    public  static  int kMP(String str1,String str2,int[] next){
        for (int i = 0 ,j=0; i <str1.length() ; i++) {

            /*需要考虑str1.charAt(i) !=str2.charAt(j)时*/
            while (j>0&&str1.charAt(i)!=str2.charAt(j)){
                j=next[j-1];
            }

            if (str1.charAt(i) ==str2.charAt(j)){
                j++;
            }
            if (j==str2.length()){
                return i - j + 1;
            }
        }
        return -1;
    }

}

 

以上是关于数据结构 字符串 模式匹配问题 KMP算法的主要内容,如果未能解决你的问题,请参考以下文章

数据结构 字符串 模式匹配问题 KMP算法

Java数据结构之字符串模式匹配算法---KMP算法

数据结构与算法简记--字符串匹配KMP算法

数据结构(C语言版)严蔚敏(字符串的模式匹配算法--KMP算法)

数据结构(C语言版)严蔚敏(字符串的模式匹配算法--KMP算法)

数据结构(C语言版)严蔚敏(字符串的模式匹配算法--KMP算法)