在朴素的模式匹配算法中,主串的pos值(i)是不断地回溯来完成的(见字符串的基本操作中的Index函数)。而计算机的大仙们发现这种回溯其实可以是不需要的。既然i值不回溯,也就是不可以变小,那么考虑的变化就是子串的pos值(j)了。通过分析发现子串中如果有相等字符,j值的变化就会不相同,也就是说,这个j值的变化跟主串其实没什么关系,关键就取决于子串的结构中是否有重复的问题。

我们把子串各个位置的j值变化定义为一个数组next,那么next的长度就是子串的长度(next[0]空置)。于是可以得到下面的函数定义。

下面摘录一段阮一峰所写关于kmp的文章,增进理解:

因为空格与C 不匹配,搜索词还要继续往后移。这时,已匹配的字符数为2("AB"),对应的"部分匹配值"为0。所以,移动位数 = 2 - 0,结果为 2,于是将搜索词向后移2位。
"部分匹配值"就是"前缀"和"后缀"的最长的共有元素的长度。以"ABC"为例,
  - "A"的前缀和后缀都为空集,共有元素的长度为0;
  - "AB"的前缀为[A],后缀为[B],共有元素的长度为0;
  - "ABC"的前缀为[A, AB],后缀为[BC, C],共有元素的长度0;

示例代码:(改编自《大话数据结构》)

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
 
#include<iostream>
using namespace std;

#define MAXSIZE 30
typedef char String[MAXSIZE + 1]; //以'\0'结尾
/* 生成一个串*/
bool StrAssign(String Dest, char *ptr)
{
    cout << "Assign Str ..." << endl;
    int i;
    for (i = 0; ptr[i] != '\0' && i < MAXSIZE; i++)
        Dest[i] = ptr[i];
    Dest[i] = '\0';
    return true;
}

int StrLength(String Src)
{
    int i = 0;
    while (Src[i] != '\0')
        i++;
    return i;
}

void StrPrint(String Src)
{
    cout << "Print Str ..." << endl;
    for (int i = 0; Src[i] != '\0'; i++)
        cout << Src[i];
    cout << endl;

}
/* 通过计算返回子串Sub的next数组。 */
void GetNext(String Sub, int *next)
{
    int i = 1;
    int j = 0;
    next[1] = 0;
    while (i < StrLength(Sub))
    {
        if(j == 0 || Sub[i - 1] == Sub[j - 1])
        {
            ++i;
            ++j;
            next[i] = j;
        }
        else
            j = next[j];/* 若字符不相同,则j值回溯 */
    }
}

void GetNextVal(String Sub, int *nextval)
{
    int i = 1;
    int j = 0;
    nextval[1] = 0;
    while (i < StrLength(Sub))
    {
        if(j == 0 || Sub[i - 1] == Sub[j - 1])
        {
            ++i;
            ++j;
            if (Sub[i - 1] != Sub[j - 1]) /* 若当前字符与前缀字符不同 */
                nextval[i] = j;/* 则当前的j为nextval在i位置的值 */
            else
                nextval[i] = nextval[j];/* 如果与前缀字符相同,则将前缀字符的 */
            /* nextval值赋值给nextval在i位置的值 */
        }
        else
            j = nextval[j];
    }
}
/* 返回子串Sub在主串Src中第pos个字符之后的位置。若不存在,则函数返回值为0。 */
int IndexKMP(String Src, String Sub, int pos)
{
    cout << "KMP Index ..." << endl;
    int i = pos - 1;
    int j = 0;
    int next[10];
    int len1 = StrLength(Src);
    int len2 = StrLength(Sub);
    /*GetNext(Sub, next);*/
    GetNextVal(Sub, next);

while (i < len1 && j < len2)
    {
        /* 两字母相等则继续,与朴素算法增加了j=0判断 */
        if (j == 0 || Src[i -1] == Sub[j -
1])
        {
            ++i;
            ++j;
        }
        else
        {
            j = next[j];/* j退回合适的位置,i值不变 */
        }
    }

if (j == len2)
        return i - len2 + 1;
    else
        return 0;
}

int main(void)
{
    String Str1, Str2, Str3, Str4;
    StrAssign(Str1, "defewabcabxwfew");
    StrAssign(Str2, "abcabx");
    StrAssign(Str3, "ababaaaba");
    StrAssign(Str4, "htrhdhsgtrhababaaabafwrew");

int next[10]; //next[0]空置
    GetNext(Str2, next);
    cout << "Get Next array ..," << endl;
    for (int i = 1; i < 7; i++)
        cout << next[i];
    cout << endl;

GetNext(Str3, next);
    cout << "Get Next array ..," << endl;
    for (int i = 1; i < 10; i++)
        cout << next[i];
    cout << endl;

GetNextVal(Str3, next);
    cout << "Get NextVal array ..," << endl;
    for (int i = 1; i < 10; i++)
        cout << next[i];
    cout << endl << endl;

cout << IndexKMP(Str1, Str2, 1) << endl;
    cout << IndexKMP(Str4, Str3, 1) << endl;

return 0;
}

输出为:

字符串 - KMP模式匹配的更多相关文章

  1. 字符串的朴素模式和KMP模式匹配

    先复习一下字符串指针: #include <iostream> #include <string.h> using namespace std; int main() { ch ...

  2. KMP模式匹配_2

    http://blog.csdn.net/lin_bei/article/details/1252686 三. 怎么求串的模式值next[n] 定义: (1)next[0]= -1 意义:任何串的第一 ...

  3. YTU 2297: KMP模式匹配 三(串)

    2297: KMP模式匹配 三(串) 时间限制: 1 Sec  内存限制: 128 MB 提交: 25  解决: 16 [提交][状态][讨论版] [Edit] [TestData] 题目描述 输入一 ...

  4. YTU 2295: KMP模式匹配 一(串)

    2295: KMP模式匹配 一(串) 时间限制: 1 Sec  内存限制: 128 MB 提交: 32  解决: 22 题目描述 求子串的next值,用next数组存放,全部输出 输入 输入一个字符串 ...

  5. KMP模式匹配 三(弦)

    原文请訪问我的博客:xiaoshig.sinaapp.com KMP模式匹配 三(串) Time Limit:1000MS     Memory Limit:131072KB     64bit IO ...

  6. KMP算法 KMP模式匹配 一(串)

    A - KMP模式匹配 一(串) Crawling in process... Crawling failed Time Limit:1000MS     Memory Limit:131072KB  ...

  7. 字符串的模式匹配(Java实现)

    字符串的模式匹配 字串的定位操作通常称做模式匹配,是各种串处理系统中最重要的操作之一.本文主要介绍两种常用的实现算法: 1.暴力匹配 2.KMP算法 1.暴力匹配 时间复杂度为O(n*m):n为主串长 ...

  8. 2295: KMP模式匹配 一(串)

    2295: KMP模式匹配 一(串) 时间限制: 1 Sec  内存限制: 128 MB提交: 210  解决: 97[提交][状态][讨论版][命题人:外部导入] 题目描述 求子串的next值,用n ...

  9. YTU 2296: KMP模式匹配 二(串)

    2296: KMP模式匹配 二(串) 时间限制: 1 Sec  内存限制: 128 MB 提交: 29  解决: 17 题目描述 输入一个主串和一个子串,用KMP进行匹配,问进行几趟匹配才成功,若没成 ...

随机推荐

  1. Android下的Junit测试

    Android SDK 1.5已经将JUnit包含进来了,用过一次,昨天晚上重新用的时候还出了一点问题,还是决定写一篇比较详细的文章,供大家和自己以后使用,写起来也挺方便的,Android下的Juni ...

  2. 任务栈 启动模式 Task Flag launchMode MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  3. 关于C++ 中POD类型的解析

    转自: http://liuqifly.spaces.live.com/blog/cns!216ae3a149106df9!221.entry (C++-98:1.8;5)给出的定义:将对象的各字节拷 ...

  4. Android Studio安装&&安装bug

    1.安装SDK:Android SDK安装 2.安装Android Studio 3.配置HTTP Proxy: 转自:Android Studio设置HTTP代理(可用) 因为大陆的内网的防火墙很厉 ...

  5. 思维导图软件xmind和mindmanager哪个更好

    思维导图是一种将放射性思考具体化的方法,可以将人们的创造性思维及时捕捉并呈现,目前便捷的网络为人们带来了众多的思维导图软件,而在这些软件中只有亲身实践体验过,才能知道到底思维导图哪个好,哪个又适合自己 ...

  6. chrome的护眼插件

  7. (C语言)memcpy函数原型的实现

    在网上看到一道题,实现一个memcpy函数,于是查了一下memcpy的函数原型,如下: void* memcpy(char *strDest, const char *strSrc, int Coun ...

  8. leetcode笔记:Sqrt(x)

    一. 题目描写叙述 Implement int sqrt(int x). Compute and return the square root of x. 二. 题目分析 该题要求实现求根公式,该题还 ...

  9. HDU1698:Just a Hook(线段树区间更新)

    Problem Description In the game of DotA, Pudge’s meat hook is actually the most horrible thing for m ...

  10. PHP 表单和用户输入

    PHP 的 $_GET 和 $_POST 用于检索表单中的值,比如用户输入. index.php页面 <?php  /*时间:2014-09-14  *作者:葛崇  *功能:表单传值小实例  * ...