KMP算法细节详解(带动图理解)(2)

简介: KMP算法细节详解(带动图理解)(2)

五、next数组细节理解

为什么按照next数组移动就可以保证不跳过匹配成功的字符串呢?

前面说过,如果匹配失败子串的首字符的位置会移动到匹配失败的位置,再向左移动next数组[i]格,匹配失败的那一位的next数组记录着前面字符的最大公共前后缀长度,由于前面的前缀都已经于主串匹配过了,只不过后缀后面的位置对不上,那么我们直接将后缀的起始位置对准匹配失败的位置,也就是向左移动next[i]个长度(也就是向左移动最大公共前后缀的长度),就能保证跳跃过程中没有错过任何可以匹配成功的串。还可以使主串中已经成功配对的后缀于子串的前缀相匹配,再向后匹配。


image.gif

下图中,①=②=③=④,所以移动回去时保证前面的后缀会与匹配失误的地方对齐

image.gif

上面展示的是有公共前后缀的情况,那么如果整个字符串都没有公共前后缀会怎么样?

  • 将发挥KMP算法的最大作用!

我们只需大胆向后跳,不用再往前跳了

此动画后半部省略掉了,找到最后没有发现相同串

image.gif

六、nextVal数组

讲完了next数组,接下来讲解nextval数组,nextVal数组是next数组的改进版,因为next数组还有改进的空间,那就是在生成数组的时候对在next数组的基础上,对失配字符的next数组下标进行读取,读取数组下标到字符串的下标位置,然后进行比较,如果不相等,那么不对其进行优化,如果读取失配讲完了next数组,接下来讲解nextval数组,nextVal数组是next数组的改进版,因为next数组还有改进的空间,那就是在生成数组的时候对在next数组的基础上,对失配字符的next数组下标进行读取,读取数组下标到字符串的下标位置,然后进行比较,如果不相等,那么不对其进行优化,如果读取失配

image.gif这样做的原理是什么呢?


1ccf3259c0c74d23bedd3f8e445a33da.png

如果此时a在与上面的字符串进行配对,那么a此时与b失配,说明对比的数是非a,按照next数组原理我们将下标为0的位置移动到上面b的位置,可是a已经和b对比过了,将下标为0的a移动过去必然也会失配,所有nextVal要先对失配的位置与next数组的值对应的下标的字符进行比较,相等就会读取其对应位置的next下标到失配位置的next下标。

七、KMP算法代码实现

讲完了原理,这里是代码实现。

  • 可以将里面的next替换为nextVal,两者都为独立的数组生成函数。
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
void getNext(int * next,const char* s,int len)
{
  assert(next && s);        //判断两个指针是不是空指针
  int i = 0, cur = -1;      //i是当前位置、cur是当前最大相同前后缀的长度
  next[0] = cur;
  while (i < len)
  {
    if (cur==-1||s[i]==s[cur])  //cur为-1的时候也要恢复成0同时i++
    {
      next[i + 1] = cur+1;
      cur++;          //cur恢复成0
      i++;        
    }
    else
    {
      cur = next[cur];    //如果失配,直接找到这个位置的next数组的值给到cur
    }
  }
}
int kmp(const char* p, const char* s)
{
  int len = strlen(s);
  int* next = (int*)malloc(sizeof(len) * len);
  getNext(next, s, len - 1);
  assert(next);
  int i = 0, j = 0;     //定义i为字符串下标,j为next数组下标
  while (p[i])        
  {
    if (j==-1||p[i] == s[j])  //如果next数组下标为-1,next数组下标恢复为0,字符串下标+1  
    {
      i++;        
      j++;    
      if (s[j] == '\0')   //如果字符串下标为‘\0’,查找成功返回i-j也就是字符串匹配成功位置的收个字符的下标
      {
        free(next);
        next = NULL;
        return i - j;
      }
    }
    else
    {
      j = next[j];      //将此位置的next数组下标对准字符串对应位置得下标
    }
  }
  free(next);
  next = NULL;
  return -1;          //如果p[字符串下标]=='\0',跳出循环,证明查找失败,返回-1
}
int main()
{
  char p[] = "abcdabecabcfdsafdasdasfdasfasdfasfdasafdsbc";
  char s[] = "abecab";
  printf("%d", kmp(p, s));
}

八、nextVal数组代码实现

void getNextVal(int *next,const char* s,int len)
{
  assert(next);
  int i = 0, cur = -1;
  next[0] = cur;
  while(i < len)
  {
    if (cur == -1 || s[i] == s[cur])  //为-1注意处理
    {
      i++;
      cur++;
      if (s[i] != s[cur])     //比next数组增加一个判断
      {
        next[i] = cur;
      }
      else
      {
        next[i] = next[cur];    //如果相等,把next[cur]的值取过来
      }
    }
    else
    {
        cur = next[cur];
    }
  }
}

完结

作者的话

KMP是一块硬骨头,建议各位能挑出一段长时间专门攻克它,不要今天看一点,明天再看一点,这样不会有收获,写代码不代表就已经真正理解了KMP,你最好要能熟练的讲给其他小伙伴KMP到底一种什么样的算法,记录一份详细的笔记,忘记的时候拿出来反复重温,最后如果觉得哪里没有理解,可以评论区留言或者私信作者,我会耐心地给大家来答疑解惑。当然如果有不足的地方还请各位帮忙补充。









































相关文章
|
22天前
|
算法 C++
A : DS串应用–KMP算法
这篇文章提供了KMP算法的C++实现,包括计算模式串的next数组和在主串中查找模式串位置的函数,用于演示KMP算法的基本应用。
|
1月前
|
算法
KMP算法
KMP算法
11 0
|
2月前
|
数据采集 算法 JavaScript
揭开JavaScript字符串搜索的秘密:indexOf、includes与KMP算法
JavaScript字符串搜索涵盖`indexOf`、`includes`及KMP算法。`indexOf`返回子字符串位置,`includes`检查是否包含子字符串。KMP是高效的搜索算法,尤其适合长模式匹配。示例展示了如何在数据采集(如网页爬虫)中使用这些方法,结合代理IP进行安全搜索。代码示例中,搜索百度新闻结果并检测是否含有特定字符串。学习这些技术能提升编程效率和性能。
揭开JavaScript字符串搜索的秘密:indexOf、includes与KMP算法
|
2月前
|
存储 算法 Python
“解锁Python高级数据结构新姿势:图的表示与遍历,让你的算法思维跃升新高度
【7月更文挑战第13天】Python中的图数据结构用于表示复杂关系,通过节点和边连接。常见的表示方法是邻接矩阵(适合稠密图)和邻接表(适合稀疏图)。图遍历包括DFS(深度优先搜索)和BFS(广度优先搜索):DFS深入探索分支,BFS逐层访问邻居。掌握这些技巧对优化算法和解决实际问题至关重要。**
26 1
|
2月前
|
数据采集 存储 算法
「AIGC算法」图搜索算法详解
本文探讨了图搜索算法,包括遍历和最短路径搜索。DFS和BFS是遍历算法,前者使用栈深入搜索,后者用队列逐层遍历。Dijkstra、Bellman-Ford、A*、Floyd-Warshall和Johnson算法则解决最短路径问题。文中还给出了DFS的Python实现示例。这些算法在路径规划、网络分析等领域有重要应用。
31 0
|
2月前
|
算法 Java
KMP算法详解及其在字符串匹配中的应用
KMP算法详解及其在字符串匹配中的应用
|
3月前
|
人工智能 算法 BI
一篇文章讲明白KMP算法(俗称看毛片算法)
一篇文章讲明白KMP算法(俗称看毛片算法)
34 0
|
3月前
|
算法 Java
Java数据结构与算法:字符串匹配算法之KMP算法
Java数据结构与算法:字符串匹配算法之KMP算法
|
14天前
|
算法 BI Serverless
基于鱼群算法的散热片形状优化matlab仿真
本研究利用浴盆曲线模拟空隙外形,并通过鱼群算法(FSA)优化浴盆曲线参数,以获得最佳孔隙度值及对应的R值。FSA通过模拟鱼群的聚群、避障和觅食行为,实现高效全局搜索。具体步骤包括初始化鱼群、计算适应度值、更新位置及判断终止条件。最终确定散热片的最佳形状参数。仿真结果显示该方法能显著提高优化效率。相关代码使用MATLAB 2022a实现。
|
14天前
|
算法 数据可视化
基于SSA奇异谱分析算法的时间序列趋势线提取matlab仿真
奇异谱分析(SSA)是一种基于奇异值分解(SVD)和轨迹矩阵的非线性、非参数时间序列分析方法,适用于提取趋势、周期性和噪声成分。本项目使用MATLAB 2022a版本实现从强干扰序列中提取趋势线,并通过可视化展示了原时间序列与提取的趋势分量。代码实现了滑动窗口下的奇异值分解和分组重构,适用于非线性和非平稳时间序列分析。此方法在气候变化、金融市场和生物医学信号处理等领域有广泛应用。