在朴素的模式匹配算法中,主串的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. Anagrams leetcode java

    题目: Given an array of strings, return all groups of strings that are anagrams. Note: All inputs will ...

  2. MyBatis两张表字段名相同产生的问题

    MyBatis两张表字段名相同, 会导致bean属性都映射为第一个表的列, 解决方法: 通过设置别名的方式让其产生区别,如 <select id="queryBySekillId&qu ...

  3. vue-router 懒加载优化

    一.路由懒加载 1.先安装 babel 动态引入插件 npm install --save-dev babel-plugin-syntax-dynamic-import 2.修改router/inde ...

  4. python3 UnicodeEncodeError: 'gbk' codec can't encode character '\xa0' in position 30: illegal multibyte sequence

    昨天用用python3写个日志文件,结果报错UnicodeEncodeError: 'gbk' codec can't encode character '\xa0' in position 30: ...

  5. GridControl 分组排序

    方法一:纯代码 this.list.gridControl.ItemsSource = lsItem; this.list.gridControl.GroupBy("GroupTitle&q ...

  6. THINKPHP URL模块大小写导致404问题

    最近我使用THINKPHP开发了一个项目在本地的集成开发环境wampserver做开发时并没有出现问题 上传到linux系统也没有出现问题,但当上传到windows平台上就出现了问题"文件4 ...

  7. 如何用命令行管理windows记住的用户名和密码

    cmdkey https://technet.microsoft.com/en-us/library/cc754243.aspx

  8. ZH奶酪:在博客中添加Latex公式

    1. 点击编辑器中的插入图片: 2.在URL输入下边的地址: http://latex.codecogs.com/gif.latex?你的latex代码 就可以了-

  9. UVALive 2949 Elevator Stopping Plan(二分 + 贪心)

    ZSoft Corp. is a software company in GaoKe Hall. And the workers in the hall are very hard-working. ...

  10. 策略模式(Strategy)简介

    一.策略模式(Strategy)简介 策略模式是行为模式. 行为模式:规定了各个对象应该具备的职责以及对象间的通信模式,它很好的规范了对象间调用和数据传递方式 策略模式适合于算法经常变化的情况 算法的 ...