串匹配问题 (KMP算法) 详解
串这个概念对于我们学到现在的水平来说应该是经历颇丰了,因为在C语言中我们所用到的“串”知识是在字符串那里,有了这个概念,我们再去学习串就相对而言轻松多了。
那么,现在来介绍一下字符串的基本知识点吧:
首先,所谓的串:
1.都由ASCII码组成;
2.长度基本没有要求
串的表示方式:
1.顺序存储结构——数组
2.非线性存储结构——链表
那么,我们在C语言中对于串的处理,一般无非是以下几种:
1.初始化“串”;
2.销毁“串”;
3.获取“串”长度;
4.插入单字符;
5.删除单字符;
6.定位单字符;
7.更改单字符;
8.取子串;
9.分割单字符;
10.合并单字符;
11.串匹配;
12.替换
这里和我们之前博文中对于 链表 和 表达式 的处理思想近乎相同,这里就不进行枯燥的复述了
那么,在这篇博文中,本人主要讲解一个算法来解决字符串匹配问题——KMP算法
首先,本人来解释一下什么是字符串匹配问题:
字符串匹配问题:
在一个源字符串中,查找一个目标字符串(子字符串)的第一次出现位置。
本人现在这里来阐释一下算法的基本思想:
根据给出的字串,得到一个数组,来储存当子串中的每一个元素的适配个数,然后根据这个数组中的值,遍历并比较源串和子串,当遇到不匹配的位置,读取该位置的适配字符数,将该数作为再次比较时源串的开始下表下标,因为我们这些。
那么,什么是适配呢?
适配就是指:与该字符紧挨着的前缀的字符串的部分长度,与从该字符串刚开始开始比较,长度相等、内容也完全相等的长度。
假设现在有一个字符串:
annbcdanacadsannannabnna
现在要求查找如下字串:
annacanna
那么,本人根据子串的信息来得出一个数组:
| 下标 | 字符 | 适配字符数 | 适配串 |
|---|---|---|---|
| 0 | a | 0 | |
| 1 | n | 0 | |
| 2 | n | 0 | |
| 3 | a | 0 | |
| 4 | c | 1 | a |
| 5 | a | 0 | |
| 6 | n | 0 | |
| 7 | n | 1 | a |
| 8 | a | 0 |
next[] = {0, 0, 0, 0, 1, 0, 0. 0}
这个例子其实算是比较简单的,还不能完全体现我们要初始化这个数组的原理,现在本人来给出一个比较复杂的例子:
源串:aabaabaabaabaabaaaabaabaab
子串:aabaabaaaabaa
那么,本人根据子串的信息来得出一个数组:
| 下标 | 字符 | 适配字符数 | 适配串 |
|---|---|---|---|
| 0 | a | 0 | |
| 1 | a | 0 | |
| 2 | b | 1 | a |
| 3 | a | 0 | |
| 4 | a | 1 | a |
| 5 | b | 2 | aa |
| 6 | a | 3 | aab |
| 7 | a | 4 | aaba |
| 8 | a | 5 | aabaa |
| 9 | a | 2 | aa |
| 10 | b | 2 | aa |
| 11 | a | 3 | aab |
| 12 | a | 4 | aaba |
next[] = {0, 0, 1, 0, 1, 2, 3, 4, 5, 2, 2, 3, 4}
现在,本人来通过两张图来展示下这个数组的作用:

没错,这个数组就是当子串和源串相比失配时应该移动的长度。
那么,了解了上述的算法的大致流程,我们现在就来用代码来实现一下:
首先,还是先来编写本人一贯的头文件:
mec.h:
#ifndef _MEC_H_
#define _MEC_H_
typedef unsigned char boolean;
#define TRUE 1
#define FALSE 0
#define NOT_FOUND -1
#endif
KMPSearch.c:
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include "mec.h"
void getNext(const char *str, int *next);
int KMPMatch(const char *str, const char *sub);
/*通过KMP算法查找字串位置 函数*/
int KMPMatch(const char *str, const char *sub) { //因为我们只是要查找位置,所以不能对 源串 以及 子串 进行更改
int *next;
int strLen; //用于存储 源串 长度
int subLen; //用于存储 子串 长度
int i = 0;
int j = 0;
if (NULL == str || NULL == sub
|| (subLen = strlen(sub)) > (strLen = strlen(str))) {
return NOT_FOUND;
}
next = (int *) calloc(sizeof(int), subLen); //我们将next数组的长度定为字串长度为了之后直接跳过不会适配的长度
getNext(sub, next);
while (str[i] && sub[j]) {
if (str[i] != sub[j]) {
if (j == 0) {
++i;
} else {
j = next[j];
//因为目标串失配点的前面的部分适配子串 和 目标串开头的部分子串内容是一样的,所以不用考虑开头那部分子串
//所以我们跳过比较这段字符串,从后面的子串开始比较,
}
} else {
++i;
++j;
}
if (sub[j] == 0) { //当我们比较到字串的下标为j时,发现子串被遍历完了,也就意味着这时子串在源串中的位置找到了
free(next);
return i - j; //因为字串长度是j,所以子串的第一个字符在源串中所对应的下标应改为当前下标(即i)- j
}
}
free(next);
return NOT_FOUND;
}
/*产生适配数组 函数*/
void getNext(const char *str, int *next) {
int i = 2;
int j = 0;
boolean isSame;
if (strlen(str) < 3) { //因为我们之后从源串的第三个单元找起,所以长度不能小于3
return;
}
while (str[i]) { //遍历 源串,查找适配点
isSame = str[i-1] == str[j];
if (isSame || j == 0) {
next[i++] = !isSame ? 0 : ++j;
} else {
j = next[j];
}
}
}
int main() {
char str[80];
char sub[80];
int index;
printf("请输入源串:");
gets(str);
printf("请输入子串:");
gets(sub);
index = KMPMatch(str, sub);
if (NOT_FOUND == index) {
printf("未找到!\n");
} else {
printf("在第%d个位置!\n", index+1); //因为数组的下标是从0开始,所以我们在表示时,要给 下标+1
}
return 0;
}
下面,我们来看一下运行结果:
可以看到,查找结果是正确的!
那么,现在本人再给出一对不存在包含关系的源串与子串,让我们再来看看查找结果:
我们能够清晰地看到,运行结果都是正确的!
串匹配问题 (KMP算法) 详解的更多相关文章
- 字符串匹配的KMP算法详解及C#实现
字符串匹配是计算机的基本任务之一. 举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串"ABCDABD" ...
- KMP算法详解&&P3375 【模板】KMP字符串匹配题解
KMP算法详解: KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt(雾)提出的. 对于字符串匹配问题(such as 问你在abababb中有多少个 ...
- kmp算法详解
转自:http://blog.csdn.net/ddupd/article/details/19899263 KMP算法详解 KMP算法简介: KMP算法是一种高效的字符串匹配算法,关于字符串匹配最简 ...
- [转] KMP算法详解
转载自:http://www.matrix67.com/blog/archives/115 KMP算法详解 如果机房马上要关门了,或者你急着要和MM约会,请直接跳到第六个自然段. 我们这里说的K ...
- KMP算法详解(转自中学生OI写的。。ORZ!)
KMP算法详解 如果机房马上要关门了,或者你急着要和MM约会,请直接跳到第六个自然段. 我们这里说的KMP不是拿来放电影的(虽然我很喜欢这个软件),而是一种算法.KMP算法是拿来处理字符串匹配的.换句 ...
- 数据结构4.3_字符串模式匹配——KMP算法详解
next数组表示字符串前后缀匹配的最大长度.是KMP算法的精髓所在.可以起到决定模式字符串右移多少长度以达到跳跃式匹配的高效模式. 以下是对next数组的解释: 如何求next数组: 相关链接:按顺序 ...
- 算法进阶面试题01——KMP算法详解、输出含两次原子串的最短串、判断T1是否包含T2子树、Manacher算法详解、使字符串成为最短回文串
1.KMP算法详解与应用 子序列:可以连续可以不连续. 子数组/串:要连续 暴力方法:逐个位置比对. KMP:让前面的,指导后面. 概念建设: d的最长前缀与最长后缀的匹配长度为3.(前缀不能到最后一 ...
- 字符串匹配KMP算法详解
1. 引言 以前看过很多次KMP算法,一直觉得很有用,但都没有搞明白,一方面是网上很少有比较详细的通俗易懂的讲解,另一方面也怪自己没有沉下心来研究.最近在leetcode上又遇见字符串匹配的题目,以此 ...
- 字符串匹配的Boyer-Moore算法 详解 加 C# 实现
上一篇文章,我介绍了KMP算法. 但是,它并不是效率最高的算法,实际采用并不多.各种文本编辑器的"查找"功能(Ctrl+F),大多采用Boyer-Moore算法. Boyer-Mo ...
随机推荐
- sql-lib闯关61-65
第六十一关 和六十关基本一样,就是变成了单引号和双括号,这好像是第一次遇见双括号 爆数据库名 ?id=1'))and extractvalue(1, concat(0x5c, (select da ...
- 使用Keras进行深度学习:(一)Keras 入门
欢迎大家关注我们的网站和系列教程:http://www.tensorflownews.com/,学习更多的机器学习.深度学习的知识! Keras是Python中以CNTK.Tensorflow或者Th ...
- Python第十一章-常用的核心模块01-collections模块
python 自称 "Batteries included"(自带电池, 自备干粮?), 就是因为他提供了很多内置的模块, 使用这些模块无需安装和配置即可使用. 本章主要介绍 py ...
- Codeforces 1332F - Independent Set(树dp)
题目链接 题意 给出一棵 n 个点的树, 求它的所有非空诱导子图的独立集种类数之和, 对 998244353 取模. n ≤ 3e5. 题解 不妨假设在独立集中的点被染色成 1, 其余不染色; 由于不 ...
- 最适合新手入门的SpringCloud教程 6—Ribbon负载均衡「F版本」
SpringCloud版本:Finchley.SR2 SpringBoot版本:2.0.3.RELEASE 源码地址:https://gitee.com/bingqilinpeishenme/Java ...
- ARDUINO UNO数字引脚端口上电后不稳定状态。
ARDUINO UNO数字引脚端口上电后不稳定状态. 在使用4*4矩阵键盘时,遇到了输入端的电平无法稳定,一直被识别为高电平. 在发现这一问题后,首先检查程序是否出错.检查后发现程序没有任何问题. 于 ...
- 白话web安全
伤心往事 梦回大二,那时候沉迷于毒奶粉,甚至国庆都在宿舍与毒奶粉共同度过,但是却发生了一件让我迄今难忘的事情~ 我新练的黑暗武士被盗了!!!干干净净!!! 虽然过了好久了,但是记忆犹新啊,仿佛发生在昨 ...
- element的多文件上传
项目需求: 可上传多个文件 可删除 文件过大时用户输入可上传至其他网站,并将文件名和地址上传至本网站 问题点: 大文件用户输入内容无法合并到已上传文件的列表进行展示 上传多个大文件地址时前面已上传的大 ...
- Java 程序该怎么优化?(技巧篇)
搬砖者:为什么程序总是那么慢?它现在到底在干什么?时间都花到哪里去了? 面试官:简单谈谈 Java 程序性能优化? 1. 字符串处理优化,乃优化之源. 研发过程中,String 的 API 用的应该是 ...
- 从JDK源码学习Arraylist
从今天开始从源码去学习一些Java的常用数据结构,打好基础:) Arraylist源码阅读: jdk版本:1.8.0 首先看其构造方法: 构造方法一: 第一种支持初始化容量大小,其中声明一个对象数组, ...