kmp算法c语言
C语言常用算法总结
C语言常用算法总结1、冒泡排序算法:冒泡排序是一种简单的排序算法,它重复地遍历要排序的序列,一次比较两个相邻的元素如果他们的顺序错误就把他们交换过来。
时间复杂度为O(n^2)。
2、快速排序算法:快速排序是一种基于分治的排序算法,通过递归的方式将数组划分为两个子数组,然后对子数组进行排序最后将排好序的子数组合并起来。
时间复杂度为O(nlogn)。
3、插入排序算法:插入排序是一种简单直观的排序算法,通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描找到相应位置并插入。
时间复杂度为O(n^2)。
4、选择排序算法:选择排序是一种简单的排序算法,每次循环选择未排序部分的最小元素,并放置在已排序部分的末尾。
时间复杂度为O(n^2)。
5、归并排序算法:归并排序是一种稳定的排序算法,基于分治思想,将数组递归地分为两个子数组,将子数组排序后再进行合并最终得到有序的数组。
时间复杂度为O(nlogn)。
6、堆排序算法:堆排序是一种基于完全二叉堆的排序算法,通过构建最大堆或最小堆,然后依次将堆顶元素与末尾元素交换再调整堆,得到有序的数组。
时间复杂度为O(nlogn)。
7、二分查找算法:二分查找是一种在有序数组中查找目标元素的算法,每次将待查找范围缩小一半,直到找到目标元素或范围为空。
时间复杂度为O(logn)。
8、KMP算法:KMP算法是一种字符串匹配算法,通过利用模式字符串的自重复性,避免不必要的比较提高匹配效率。
时间复杂度为O(m+n),其中m为文本串长度,n为模式串长度。
9、动态规划算法:动态规划是一种通过将问题分解为子问题,并通过组合子问题的解来求解原问题的方法。
动态规划算法通常使用内存空间来存储中间结果,从而避免重复计算。
时间复杂度取决于问题规模。
10、贪心算法:贪心算法是一种通过选择局部最优解来构建全局最优解的算法并以此构建最终解。
时间复杂度取决于问题规模。
11、最短路径算法:最短路径算法用于求解图中两个节点之间的最短路径,常见的算法包括Dijkstra算法和Floyd-Warshall算法。
KMP算法以及优化(代码分析以及求解next数组和nextval数组)
KMP算法以及优化(代码分析以及求解next数组和nextval数组)KMP算法以及优化(代码分析以及求解next数组和nextval数组)来了,数据结构及算法的内容来了,这才是我们的专攻,前⾯写的都是开胃⼩菜,本篇⽂章,侧重考研408⽅向,所以保证了你只要看懂了,题⼀定会做,难道这样思想还会不会么?如果只想看next数组以及nextval数组的求解可以直接跳到相应部分,思想总结的很⼲~~⽹上的next数组版本解惑先总结⼀下,⼀般KMP算法的next数组结果有两个版本,我们需要知道为什么会存在这种问题,其实就是前缀和后缀没有匹配的时候next数组为0还是为1,两个版本当然都是对的了,如果next数组为0是的版本,那么对于前缀和后缀的最⼤匹配长度只需要值+1就跟next数组是1的版本⼀样了,其实是因为他们的源代码不⼀样,或者对于模式串的第⼀个下标理解为0或者1,总之这个问题不⽤纠结,懂原理就⾏~~那么此处,我们假定前缀和后缀的最⼤匹配长度为0时,next数组值为1的版本,考研⼀般都是⽤这个版本(如果为0版本,所有的内容-1即可,如你算出next[5]=6,那么-1版本的next[5]就为5,反之亦然)~~其实上⾯的话总结就是⼀句话next[1]=0,j(模式串)数组的第⼀位下标为1,同时,前缀和后缀的最⼤匹配长度+1即为next数组的值,j所代表的的是序号的意思408反⼈类,⼀般数组第⼀位下标为1,关于书本上前⾯链表的学习⼤家就应该有⽬共睹了,书本上好多数组的第⼀位下标为了⽅便我们理解下标为1,想法这样我们更不好理解了,很反⼈类,所以这⾥给出next[1]=0,前缀和后缀的最⼤匹配长度+1的版本讲解前⾔以及问题引出我们先要知道,KMP算法是⽤于字符串匹配的~~例如:⼀个主串"abababcdef"我们想要知道在其中是否包括⼀个模式串"ababc"初代的解决⽅法是,朴素模式匹配算法,也就是我们主串和模式串对⽐,不同主串就往前移⼀位,从下⼀位开始再和模式串对⽐,每次只移动⼀位,这样会很慢,所以就有三位⼤神⼀起搞了个算法,也就是我们现在所称的KMP算法~~代码以及理解源码这⾥给出~~int Index_KMP(SString S,SString T,intt next[]){int i = 1,j = 1;//数组第⼀位下标为1while (i <= S.length && j <= T.length){if (j == 0 || S.ch[i] == T.ch[j]){//数组第⼀位下标为1,0的意思为数组第⼀位的前⾯,此时++1,则指向数组的第⼀位元素++i;++j; //继续⽐较后继字符}elsej = next[j]; //模式串向右移动到第⼏个下标,序号(第⼀位从1开始)}if (j > T.length)return i - T.length; //匹配成功elsereturn 0;}接下来就可以跟我来理解这个代码~~还不会做动图,这⾥就⼿画了~~以上是⼀般情况,那么如何理解j=next[1]=0的时候呢?是的,这就是代码的思路,那么这时我们就知道,核⼼就是要求next数组各个的值,对吧,⼀般也就是考我们next数组的值为多少~~next数组的求解这⾥先需要给出概念,串的前缀以及串的后缀~~串的前缀:包含第⼀个字符,且不包含最后⼀个字符的⼦串串的后缀:包含最后⼀个字符,且不包含第⼀个字符的⼦串当第j个字符匹配失败,由前1~j-1个字符组成的串记为S,则:next[j]=S的最长相等前后缀长度+1与此同时,next[1]=0如,模式串"ababaa"序号J123456模式串a b a b a anext[j]0当第六个字符串匹配失败,那么我们需要在前5个字符组成的串S"ababa"中找最长相等的前后缀长度为多少再+1~~如串S的前缀可以为:"a","ab","aba","abab",前缀只不包括最后⼀位都可串S的后缀可以为:"a","ba","aba","baba",后缀只不包括第⼀位都可所以这⾥最⼤匹配串就是"aba"长度为3,那么我们+1,取4序号J123456模式串a b a b a anext[j]04再⽐如,当第⼆个字符串匹配失败,由前1个字符组成的串S"a"中,我们知道前缀应当没有,后缀应当没有,所以最⼤匹配串应该为0,那么+1就是取1~~其实这⾥我们就能知道⼀个规律了,next[1]⼀定为0(源码所造成),next[2]⼀定为1(必定没有最⼤匹配串造成)~~序号J123456模式串a b a b a anext[j]014再再⽐如,第三个字符串匹配失败,由前两个字符组成的串S"ab"中找最长相等的前后缀长度,之后再+1~~前缀:"a"后缀:"b"所以所以这⾥最⼤匹配串也是没有的长度为0,那么我们+1,取1序号J123456模式串a b a b a anext[j]0114接下来你可以⾃⼰练练4和5的情况~~next[j]011234是不是很简单呢?⾄此,next数组的求法以及kmp代码的理解就ok了~~那么接下来,在了解以上之后,我们想⼀想KMP算法存在的问题~~KMP算法存在的问题如下主串:"abcababaa"模式串:"ababaa"例如这个问题我们很容易能求出next数组序号J123456模式串a b a b a anext[j]011234此时我们是第三个字符串匹配失败,所以我们的next[3]=1,也就是下次就是第⼀个字符"a"和主串中第三个字符"c"对⽐,可是我们刚开始的时候就已经知道模式串的第三个字符"a"和"c"不匹配,那么这⾥不就多了⼀步⽆意义的匹配了么?所以我们就会有kmp算法的⼀个优化了~~KMP算法的优化我们知道,模式串第三个字符"a"不和主串第三个字符"c"不匹配,next数组需要我们的next[3]=1,也就是下次就是第⼀个字符"a"和主串中第三个字符"c"对⽐,之后就是模式串第⼀个字符"a"不和"c"匹配,就是需要变为next[1]=0,那么我们要省去步骤,不就可以直接让next[3]=0么?序号J12345模式串a b a b anext[j]01123nextval[j]00那么怎么省去多余的步骤呢?这就是nextval数组的求法~~nextval的求法以及代码理解先贴出代码for (int j = 2;j <= T.length;j++){if (T.ch[next[j]] == T.ch[j])nextval[j] = nextval[next[j]];elsenextval[j] = next[j];}如序号J123456模式串a b a b a anext[j]011234nextval[j]0⾸先,第⼀次for循环,j=2,当前序号b的next[2]为1,即第⼀个序号所指向的字符a,a!=当前序号b,所以nextval[2]保持不变等于next[2]=1序号J123456模式串a b a b a anext[j]011234nextval[j]01第⼆次for循环,j=3,当前序号a的next[3]为1,即第⼀个序号所指向的字符a,a=当前序号a,所以nextval[3]等于nextval[1]=0序号J123456模式串a b a b a anext[j]011234nextval[j]010第三次for循环,j=4,当前序号b的next[4]为2,即第⼆个序号所指向的字符b,b=当前序号b,所以nextval[4]等于nextval[2]=1序号J123456模式串a b a b a anext[j]011234nextval[j]0101就是这样,你可以练练5和6,这⾥直接给出~~序号J123456模式串a b a b a anext[j]011234nextval[j]010104⾄此nextval数组的求法你也应该会了,那么考研要是考了,那么是不是就等于送分给你呢?⼩练习那么你试着来求⼀下这个模式串的next和nextval数组吧~~next[j]nextval[j]⼩练习的答案序号j12345模式串a a a a b next[j]01234 nextval[j]00004。
c++实现KMP算法
c++实现KMP算法KMPKMP算法解决的问题字符串str1和str2,str1是否包含str2,如果包含返回str2在str1中开始的位置。
如何做到时间复杂度O(N)完成?思路:⾸先判断两个字符串是否为空串,并且str2的长度是否⼩于str1的长度,因为题⽬要求str1中包含str2。
以上都满⾜的情况下,⾸先定义两个变量分别为 x ,y 作为后续字符串中字符遍历的下标,然后再⽣成⼀个vector容器next,⽤来后续的匹配加速然后在str2中,做加速操作,也就是看当前 i - 1和之前的所有字符,有没有相同的,最⼤匹配长度。
从上图可以看到,下标0和1位置的值永远都是固定的-1和0,。
x 字符是 i 位置,x 前⾯的 c 是 i - 1 位置,也就是从下标0位置到5位置,找最⼤的匹配长度,然后填到 i 的next中。
这是循环中的case1如果当next中的值⼤于0的时候,从b开始,找到next中的2位置,然后跳转到当前位置的next中的坐标上,接着进⾏匹配。
最后如果到next为0或者-1的位置上,就标记当前位置为0,然后到下⼀个坐标继续判断。
当 i 遍历完str2后,循环结束,代表next中的值已经全部设置好了。
当str1 和 str2 没有循环遍历到尾部的时候,只要 str1 中 x 的位置等于 str2 中 y 的位置,x 和 y 就同时⾃增。
如果next中的值等于 -1 ,就说没有匹配成功,x 单独⾃增。
让str1往后挪⼀位如果str2中的没有匹配成功,就往前找next数组的值,只要不等于 -1 ,就⼀直执⾏这个往前移的过程。
最后看 y 是否已经到了str2的位置,如果到了就说明找到了,直接返回 x的位置减去 y的位置,就是匹配开始的位置,否则就是没有找到,直接返回 -1void getNextArray(string str, vector<int>& next){if (str.length() == 1){next.push_back(-1);}next.resize(str.length());next[0] = -1;next[1] = 0;int i = 2;int cn = 0;while (i < next.size()){if (str[i - 1] == str[cn]){next[i++] = ++cn;}else if (cn > 0){cn = next[cn];}else {next[i++] = 0;}}}int getIndexOf(string s, string m){if (s == "" || m == "" || s.length() < 1 || s.length() < m.length()){return -1;}int x = 0;int y = 0;vector<int> next;getNextArray(m,next);while (x < s.length() && y < m.length()){if (s[x] == m[y]){x++;y++;}else if (next[y] == -1){x++;}else {y = next[y];}}return y == m.length() ? x - y : -1;}以上就是c++ 实现KMP算法的详细内容,更多关于c++ KMP算法的资料请关注其它相关⽂章!。
KMP算法详解
KMP算法详解KMP 算法详解KMP 算法是⼀个⼗分⾼效的字符串查找算法,⽬的是在⼀个字符串 s 中,查询 s 是否包含⼦字符串 p,若包含,则返回 p 在 s 中起点的下标。
KMP 算法全称为 Knuth-Morris-Pratt 算法,由 Knuth 和 Pratt 在1974年构思,同年 Morris 也独⽴地设计出该算法,最终由三⼈于1977年联合发表。
举⼀个简单的例⼦,在字符串 s = ababcabababca 中查找⼦字符串 p = abababca,如果暴⼒查找,我们会遍历 s 中的每⼀个字符,若 s[i] = p[0],则向后查询p.length() 位是否都相等。
这种朴素的暴⼒的算法复杂度为O(m×n),其中m和n分别是 p 和 s 的长度。
KMP 算法可以⽅便地简化这⼀查询的时间复杂度,达到O(m+n)。
1. PMT 序列PMT 序列是 KMP 算法的核⼼,即 Partial Match Table(部分匹配表)。
举个例⼦:char a b a b a b c aindex01234567PMT00123401PMT 的值是字符串的前缀集合与后缀集合的交集中最长元素的长度。
PMT[0] = 0: 字符串 a 既没有前缀,也没有后缀;PMT[1] = 0: 字符串 ab 前缀集合为 {a},后缀集合为 {b},没有交集;PMT[2] = 1: 字符串 aba 前缀集合为 {a, ab},后缀集合为 {ba, a},交集为 {a},交集元素的最长长度为1;PMT[3] = 2: 字符串 abab 前缀集合为 {a, ab, aba},后缀集合为 {bab, ab, b},交集为 {ab},交集元素的最长长度为2;…… 以此类推。
2. 算法主体现在我们已经知道了 PMT 序列的含义,那么假设在 PMT 序列已经给定的情况下,如何加速字符串匹配算法?tar 存储 s 的下标,从 0 开始,若 tar > s.length() - 1,代表匹配失败;pos 存储 p 的下标,从 0 开始,若 s[tar] != p[pos],则 pos ⾛到下⼀个可能匹配的位置。
KMP模式匹配算法
KMP模式匹配算法KMP算法是一种字符串匹配算法,用于在一个主串中查找一个模式串的出现位置。
该算法的核心思想是通过预处理模式串,构建一个部分匹配表,从而在匹配过程中尽量减少不必要的比较。
KMP算法的实现步骤如下:1.构建部分匹配表部分匹配表是一个数组,记录了模式串中每个位置的最长相等前后缀长度。
从模式串的第二个字符开始,依次计算每个位置的最长相等前后缀长度。
具体算法如下:-初始化部分匹配表的第一个位置为0,第二个位置为1- 从第三个位置开始,假设当前位置为i,则先找到i - 1位置的最长相等前后缀长度记为len,然后比较模式串中i位置的字符和模式串中len位置的字符是否相等。
- 如果相等,则i位置的最长相等前后缀长度为len + 1- 如果不相等,则继续判断len的最长相等前后缀长度,直到len为0或者找到相等的字符为止。
2.开始匹配在主串中从前往后依次查找模式串的出现位置。
设置两个指针i和j,分别指向主串和模式串的当前位置。
具体算法如下:-当主串和模式串的当前字符相等时,继续比较下一个字符,即i和j分别向后移动一个位置。
-当主串和模式串的当前字符不相等时,根据部分匹配表确定模式串指针j的下一个位置,即找到模式串中与主串当前字符相等的位置。
如果找到了相等的位置,则将j移动到相等位置的下一个位置,即j=部分匹配表[j];如果没有找到相等的位置,则将i移动到下一个位置,即i=i+13.检查匹配结果如果模式串指针j移动到了模式串的末尾,则说明匹配成功,返回主串中模式串的起始位置;如果主串指针i移动到了主串的末尾,则说明匹配失败,没有找到模式串。
KMP算法的时间复杂度为O(m+n),其中m为主串的长度,n为模式串的长度。
通过预处理模式串,KMP算法避免了在匹配过程中重复比较已经匹配过的字符,提高了匹配的效率。
总结:KMP算法通过构建部分匹配表,实现了在字符串匹配过程中快速定位模式串的位置,减少了不必要的比较操作。
C语言程序设计的常用算法
C语言程序设计的常用算法1.排序算法-冒泡排序:通过多次比较和交换来将最大(小)的数移到最后(前),时间复杂度为O(n^2)。
适用于数据较少、数据基本有序的情况。
- 快速排序:通过一趟排序将待排序序列分隔成独立的两部分,其中一部分的所有元素都比另一部分的所有元素小。
然后递归地对两部分进行排序,时间复杂度为O(nlogn)。
适用于大规模数据的排序。
-插入排序:将待排序序列分为已排序和未排序两部分,每次从未排序部分取一个元素插入到已排序部分的适当位置,时间复杂度为O(n^2)。
适用于数据量较小的排序场景。
- 归并排序:将待排序序列分为若干个子序列,分别进行排序,然后再将排好序的子序列合并成整体有序的序列,时间复杂度为O(nlogn)。
适用于需要稳定排序且对内存空间要求不高的情况。
2.查找算法-顺序查找:从头到尾依次对每个元素进行比较,直到找到目标元素或者遍历完整个序列。
时间复杂度为O(n)。
- 二分查找:对于有序序列,将序列的中间元素与目标元素进行比较,根据比较结果缩小查找范围,直到找到目标元素或者查找范围为空。
时间复杂度为O(logn)。
3.图算法-广度优先(BFS):从给定的起始顶点开始,按照“先访问当前顶点的所有邻接顶点,再依次访问这些邻接顶点的所有未访问过的邻接顶点”的顺序逐层访问图中的所有顶点。
适用于寻找最短路径、连通性等问题。
-深度优先(DFS):从给定的起始顶点开始,按照“先递归访问当前顶点的一个邻接顶点,再递归访问这个邻接顶点的一个邻接顶点,直到无法再继续递归”的方式遍历图中的所有顶点。
适用于寻找路径、判断连通性等问题。
4.动态规划算法-背包问题:给定一个背包容量和一组物品的重量和价值,选择一些物品装入背包,使得装入的物品总重量不超过背包容量,且总价值最大。
利用动态规划的思想可以通过构建二维数组来解决该问题。
-最长公共子序列(LCS):给定两个序列,找出一个最长的子序列,且该子序列在两个原序列中的顺序保持一致。
C语言常用算法大全
C语言常用算法大全1.排序算法-冒泡排序:依次比较相邻的两个元素,如果顺序不对则交换,每轮找出一个最大或最小的元素-选择排序:从未排序的元素中选择最小或最大的放到已排序的最后,以此类推-插入排序:将未排序的元素插入到已排序的合适位置,从后向前进行比较和交换-快速排序:选择一个基准元素,将小于基准元素的放在左边,大于基准元素的放在右边,然后对左右两边递归地进行快速排序-归并排序:将待排序的序列不断划分为左右两部分,分别排序后再将排序好的左右两部分按顺序合并-堆排序:构建大顶堆,将堆顶元素与末尾元素交换,然后重新调整堆,重复这个过程直到排序完成2.查找算法-顺序查找:从给定的元素序列中逐个比较,直到找到目标元素或遍历完整个序列-二分查找:对于有序序列,在序列的中间位置比较目标元素和中间元素的大小关系,通过每次缩小一半的范围来查找目标元素-插值查找:根据目标元素与有序序列的最小值和最大值的比例推测目标元素所在的位置,然后递归地进行查找-斐波那契查找:根据斐波那契数列的性质来确定目标元素所在的位置,然后递归地进行查找3.图算法-深度优先(DFS):从图的一些顶点出发,依次访问其未被访问过的邻接顶点,直到所有顶点都被访问过为止-广度优先(BFS):从图的一些顶点出发,逐层遍历图的顶点,直到所有顶点都被访问过为止- 最小生成树算法:Prim算法和Kruskal算法,用于找到连接图中所有顶点的最小权值边,构成一棵包含所有顶点的生成树- 最短路径算法:Dijkstra算法和Floyd-Warshall算法,用于找到图中两个顶点之间的最短路径-拓扑排序:用于有向无环图(DAG)中的顶点排序,确保排序后的顶点满足所有依赖关系-关键路径算法:找出网络中的关键路径,即使整个工程完成的最短时间4.字符串算法- KMP算法:通过预处理模式串构建next数组,利用next数组在匹配过程中跳过一部分不可能匹配的子串- Boyer-Moore算法:从模式串的末尾开始匹配,利用坏字符和好后缀规则进行跳跃匹配- Rabin-Karp算法:利用哈希函数对主串和匹配串的子串进行哈希计算,然后比较哈希值是否相等- 字符串匹配算法:BM算法、Shift-And算法、Sunday算法等,用于寻找模式串在主串中的出现位置5.动态规划算法-最长公共子序列(LCS):用于寻找两个序列中最长的公共子序列-最长递增子序列(LIS):用于寻找给定序列中最长的递增子序列-0-1背包问题:将有限的物品放入容量为C的背包中,使得物品的总价值最大-最大子数组和:用于求解给定数组中连续子数组的最大和-最大正方形:在给定的0-1矩阵中,找出只包含1的最大正方形的边长这些算法是在C语言中常用的算法,它们涵盖了排序、查找、图、字符串和动态规划等多个领域。
c语言数据结构及算法
C语言是一种广泛应用于编程和软件开发的编程语言,它提供了一系列的数据结构和算法库,使得开发者能够在C语言中使用这些数据结构和算法来解决各种问题。
以下是C语言中常用的数据结构和算法:数据结构:1. 数组(Array):一组相同类型的元素按顺序排列而成的数据结构。
2. 链表(Linked List):元素通过指针连接而成的数据结构,可分为单向链表、双向链表和循环链表等。
3. 栈(Stack):具有后进先出(LIFO)特性的数据结构,可用于实现函数调用、表达式求值等。
4. 队列(Queue):具有先进先出(FIFO)特性的数据结构,可用于实现任务调度、缓冲区管理等。
5. 树(Tree):一种非线性的数据结构,包括二叉树、二叉搜索树、堆、A VL树等。
6. 图(Graph):由节点和边组成的数据结构,可用于表示网络、关系图等。
7. 哈希表(Hash Table):基于哈希函数实现的数据结构,可用于高效地查找、插入和删除元素。
算法:1. 排序算法:如冒泡排序、插入排序、选择排序、快速排序、归并排序等。
2. 查找算法:如线性查找、二分查找、哈希查找等。
3. 图算法:如深度优先搜索(DFS)、广度优先搜索(BFS)、最短路径算法(Dijkstra、Floyd-Warshall)、最小生成树算法(Prim、Kruskal)等。
4. 字符串匹配算法:如暴力匹配、KMP算法、Boyer-Moore 算法等。
5. 动态规划算法:如背包问题、最长公共子序列、最短编辑距离等。
6. 贪心算法:如最小生成树问题、背包问题等。
7. 回溯算法:如八皇后问题、0-1背包问题等。
这只是C语言中常用的一部分数据结构和算法,实际上还有更多的数据结构和算法可以在C语言中实现。
开发者可以根据具体需求选择适合的数据结构和算法来解决问题。
同时,C语言也支持自定义数据结构和算法的实现,开发者可以根据需要进行扩展和优化。
C语言中的模式匹配算法
C语言中的模式匹配算法在计算机科学中,模式匹配是一种非常重要的算法,它可以用于文本匹配、字符串匹配、图形识别等领域。
在C语言中,有多种模式匹配算法可以用于实现字符串匹配操作。
本文将介绍C语言中的一些常用模式匹配算法,包括Brute-Force算法、Knuth-Morris-Pratt(KMP)算法和Boyer-Moore算法。
一、Brute-Force算法Brute-Force算法,也称为朴素模式匹配算法,是最简单直接的一种算法。
它的思想是从目标字符串的第一个字符开始,依次和模式字符串对应位置的字符比较,如果出现不匹配的字符,则将目标字符串的指针向后移动一位,再次进行比较,直到找到匹配的子串或遍历完整个目标字符串。
Brute-Force算法的时间复杂度为O(m*n),其中m为目标字符串的长度,n为模式字符串的长度。
该算法简单易懂,但对于较长的字符串匹配操作效率较低。
二、Knuth-Morris-Pratt(KMP)算法KMP算法是一种优化的字符串模式匹配算法,它利用了模式字符串中的信息来避免不必要的比较。
该算法的核心思想是,当模式字符串中的某一部分与目标字符串不匹配时,不需要将目标字符串的指针回溯到上一次比较的位置,而是利用已有的信息直接跳过一部分字符,从而提高了匹配的效率。
KMP算法的时间复杂度为O(m+n),其中m为目标字符串的长度,n为模式字符串的长度。
相较于Brute-Force算法,KMP算法在处理较长字符串时能够明显提高匹配速度。
三、Boyer-Moore算法Boyer-Moore算法是一种更加高效的字符串模式匹配算法,它充分利用了模式字符串中的信息进行跳跃式匹配。
该算法的核心思想包括两个关键步骤:坏字符规则和好后缀规则。
坏字符规则是通过将模式串与目标串在不匹配的位置对齐,找出目标串中不匹配的字符在模式串中最后一次出现的位置,从而跳过一部分字符的比较。
好后缀规则则是利用模式串与目标串中已匹配的部分,找出能够与好后缀匹配的最长子串,直接将模式串向后滑动到该子串的位置,从而跳过一部分字符的比较。
c语言经典算法解析
c语言经典算法解析C语言作为一种广泛使用的编程语言,拥有许多经典算法,这些算法不仅在解决实际问题上非常高效,而且对于理解计算机科学的基本原理也至关重要。
本文将介绍一些C语言中常见的经典算法,并解析其实现原理。
1. 排序算法:排序是计算机科学中最基本的问题之一,C语言提供了多种排序算法的实现,例如冒泡排序、选择排序、插入排序、快速排序等。
这些算法以不同的方式对元素进行比较和交换,最终将数据按照一定的顺序排列。
2. 查找算法:查找算法用于在给定数据集中寻找特定的值。
C语言中常见的查找算法包括线性查找、二分查找、哈希查找等。
这些算法的实现原理各不相同,但都能在不同的数据规模下高效地找到目标值。
3. 图算法:图是由节点和边组成的一种数据结构,图算法用于解决与图相关的问题,例如最短路径查找、拓扑排序、最小生成树等。
C语言中可以使用邻接矩阵或邻接表等数据结构来表示图,并通过深度优先搜索或广度优先搜索等算法来进行相应的操作。
4. 字符串匹配算法:字符串匹配算法用于在一个长字符串中查找某个子串出现的位置。
常见的算法包括朴素字符串匹配算法、KMP算法、Boyer-Moore算法等。
这些算法通过不同的方式在给定的字符串中寻找匹配,从而提高查找的效率。
5. 动态规划算法:动态规划算法用于解决有重叠子问题和最优子结构特征的问题。
C语言中常用的动态规划算法有背包问题、最长公共子序列问题、最短路径问题等。
这些算法通过将大问题分解为小问题,并使用查表或记忆化搜索等技术来避免重复计算,从而提高算法的效率。
以上仅是C语言中一些经典算法的简要介绍和解析。
随着计算机科学的不断发展,还有许多其他算法可以探索和应用。
掌握这些经典算法的原理和实现有助于提高编程技能,同时也能够帮助理解计算机科学的核心概念。
通过不断学习和实践,我们可以在编程中灵活运用这些算法,解决实际问题。
KMP算法-易懂版
KMP算法-易懂版⼀:定义 Knuth-Morris-Pratt 字符串查找算法,简称为 KMP算法,常⽤于快速查找⼀个母串S中是否包含⼦串(模式串)P,以及P出现的位置。
由于简单的暴⼒匹配中,每次遇到不匹配的位置时都要回溯到母串上⼀次的起点 i +1的位置上再次从⼦串的开头进⾏匹配,效率极其低下,故⽽KMP算法应运⽽⽣,减少回溯过程中不必要的匹配部分,加快查找速度。
⼆:kmp算法求解步骤描述 若当前不匹配的位置发⽣在母串位置 i,⼦串位置 j 上,则:1. 寻找⼦串位置 j 之前元素的最长且相等的前后缀,即最长公共前后缀。
记录这个长度。
2. 根据这个长度求 next 数组3. 若 j != 0, 则根据next [j] 中的值,将⼦串向右移动,也就是将公共前缀移到公共后缀的位置上,(代码表⽰为:j=next [j],注意 i 不变),即对位置 j 进⾏了更新,后续⼦串直接从更新后的 j 位置和母串 i 位置进⾏⽐较。
4. 若 j == 0,则 i+1,⼦串从j位置开始和母串 i+1 位置开始⽐较。
综上,KMP的next 数组相当于告诉我们:当⼦串中的某个字符跟母串中的某个字符匹配失败时,⼦串下⼀步应该跳到哪个位置开始和母串当前失配位置进⾏⽐较。
所以kmp算法可以简单解释为:如⼦串在j 处的字符跟母串在i 处的字符失配时,下⼀步就⽤⼦串next [j] 处的字符继续跟⽂本串 i 处的字符匹配,相当于⼦串⼀次向右移动 j - next[j] 位,跳过了⼤量不必要的匹配位置(OK,简单理解完毕之后,下⾯就是求解KMP的关键步骤,Let’s go! ) 三:kmp算法关键步骤之⼀,求最长的公共前后缀! 箭头表⽰当前匹配失败的位置,也就是当前的 j 位置。
⽩框表⽰最长公共前后缀AB!此时长度为2! 再来⼀个,此时最长公共前后缀为ABA!长度为3!四:kmp算法关键步骤之⼆,求next[ ] 数组 由步骤⼀,我们可以得到⼦串每个位置前⾯元素的最长共同前后缀,注意⼦串第⼀个位置是没有前后缀的,所以长度为0! 例:⼦串ABCDABD的最长公共前后缀可表⽰如下。
kmp next算法
kmp next算法KMP算法(Knuth-Morris-Pratt Algorithm)是一种字符串匹配算法,它的核心思想是利用已经得到的匹配结果,尽量减少字符的比较次数,提高匹配效率。
本文将详细介绍KMP算法的原理、实现方法以及应用场景。
一、KMP算法的原理KMP算法的核心是构建next数组,用于指导匹配过程中的回溯操作。
next数组的定义是:对于模式串中的每个字符,记录它前面的子串中相同前缀和后缀的最大长度。
next数组的长度等于模式串的长度。
具体来说,KMP算法的匹配过程如下:1. 初始化主串指针i和模式串指针j为0。
2. 逐个比较主串和模式串对应位置的字符:- 若主串和模式串的字符相等,i和j同时后移一位。
- 若主串和模式串的字符不相等,根据next数组的值,将模式串指针j回溯到合适的位置,继续匹配。
二、KMP算法的实现KMP算法的实现可以分为两个步骤:构建next数组和利用next数组进行匹配。
1. 构建next数组:- 首先,next[0]赋值为-1,next[1]赋值为0。
- 然后,从第2个位置开始依次计算next[i],根据前一个位置的next值和模式串的字符进行判断:- 若前一个位置的next值为-1或模式串的字符与前一个位置的字符相等,则next[i] = next[i-1] + 1。
- 若前一个位置的next值不为-1且模式串的字符与前一个位置的字符不相等,则通过next数组的回溯操作,将模式串指针j回溯到合适的位置,继续判断。
2. 利用next数组进行匹配:- 在匹配过程中,主串指针i和模式串指针j会同时后移:- 若主串和模式串的字符相等,i和j同时后移一位。
- 若主串和模式串的字符不相等,则根据next数组的值,将模式串指针j回溯到合适的位置,继续匹配。
三、KMP算法的应用场景KMP算法在字符串匹配中有广泛的应用,特别是在大规模文本中的模式匹配问题上具有明显的优势。
以下是KMP算法的几个应用场景:1. 子串匹配:判断一个字符串是否是另一个字符串的子串。
kmp 时间复杂度计算
kmp 时间复杂度计算摘要:一、KMP 算法简介1.KMP 算法的概念2.KMP 算法的原理3.KMP 算法的作用二、KMP 算法的时间复杂度分析1.KMP 算法的时间复杂度公式2.KMP 算法时间复杂度分析的过程3.KMP 算法相对于其他字符串匹配算法的优势三、KMP 算法在实际应用中的案例1.KMP 算法在文本处理中的应用2.KMP 算法在信息检索中的应用3.KMP 算法在自然语言处理中的应用正文:一、KMP 算法简介KMP(Knuth-Morris-Pratt)算法是一种高效的字符串匹配算法,用于在一个主字符串中查找一个子字符串出现的位置。
该算法由Donald Knuth、Charles Morris 和Vaughan Pratt 于1977 年共同提出,其核心思想是利用子字符串的前缀与后缀信息来避免不必要的字符比较,从而提高匹配速度。
1.KMP 算法的概念:KMP 算法是一种滑动窗口法,通过构建一个“部分匹配表”(也称为“失效函数”或“next 数组”),实现字符串的高效匹配。
2.KMP 算法的原理:从主字符串的第一个字符开始,将其与子字符串的第一个字符进行比较。
若相等,继续比较后续字符;若不等,根据部分匹配表的值,将子字符串向右移动若干个字符,再次进行比较。
如此循环,直至找到匹配的子字符串或到达子字符串末尾。
3.KMP 算法的作用:KMP 算法可以在O(n) 的时间复杂度内完成主字符串与子字符串的匹配,其中n 为字符串的长度。
相较于O(n^2) 的暴力匹配算法,KMP 算法具有较高的效率。
二、KMP 算法的时间复杂度分析1.KMP 算法的时间复杂度公式:最优情况下,KMP 算法的时间复杂度为O(n),其中n 为字符串的长度。
最坏情况下,KMP 算法的时间复杂度为O(n^2),此时子字符串与主字符串的前缀完全相同。
2.KMP 算法时间复杂度分析的过程:分析KMP 算法的时间复杂度,需要考虑最优情况、最坏情况和平均情况。
C语言中的字符串匹配算法实现
C语言中的字符串匹配算法实现在C语言中,字符串匹配算法用于判断一个字符串是否包含另一个字符串。
本文将介绍几种常见的字符串匹配算法及其实现。
一、暴力匹配算法(Brute-Force Algorithm)暴力匹配算法是最简单直观的字符串匹配算法,也被称为朴素字符串匹配算法。
算法思想:从主字符串的第一个字符开始,依次与模式字符串的字符逐个比较,如果出现字符不匹配的情况,则主字符串的指针后移一位,再从下一个字符开始重新比较。
实现代码示例:```c#include <stdio.h>#include <string.h>int bruteForceMatch(char *str, char *pattern) {int len1 = strlen(str);int len2 = strlen(pattern);int i = 0, j = 0;while(i < len1 && j < len2) {if(str[i] == pattern[j]) {i++;j++;} else {i = i - j + 1;j = 0;}}if(j == len2) {return i - len2; // 返回匹配位置的索引} else {return -1; // 未找到匹配}}int main() {char str[] = "Hello, world!";char pattern[] = "world";int index = bruteForceMatch(str, pattern);if(index >= 0) {printf("匹配成功,匹配位置为:%d\n", index);} else {printf("未找到匹配\n");}return 0;}```上述示例代码中,我们使用了一个bruteForceMatch函数来实现暴力匹配算法。
KMP算法
从头到尾彻底理解KMP作者:July时间:最初写于2011年12月,2014年7月21日晚10点全部删除重写成此文,随后的半个多月不断反复改进。
后收录于新书《编程之法:面试和算法心得》第4.4节中。
1. 引言本KMP原文最初写于2年多前的2011年12月,因当时初次接触KMP,思路混乱导致写也写得混乱。
所以一直想找机会重新写下KMP,但苦于一直以来对KMP的理解始终不够,故才迟迟没有修改本文。
然近期因开了个算法班,班上专门讲解数据结构、面试、算法,才再次仔细回顾了这个KMP,在综合了一些网友的理解、以及算法班的两位讲师朋友曹博、邹博的理解之后,写了9张PPT,发在微博上。
随后,一不做二不休,索性将PPT 上的内容整理到了本文之中(后来文章越写越完整,所含内容早已不再是九张PPT 那样简单了)。
KMP本身不复杂,但网上绝大部分的文章(包括本文的2011年版本)把它讲混乱了。
下面,咱们从暴力匹配算法讲起,随后阐述KMP的流程步骤、next 数组的简单求解递推原理代码求解,接着基于next 数组匹配,谈到有限状态自动机,next 数组的优化,KMP的时间复杂度分析,最后简要介绍两个KMP的扩展算法。
全文力图给你一个最为完整最为清晰的KMP,希望更多的人不再被KMP折磨或纠缠,不再被一些混乱的文章所混乱。
有何疑问,欢迎随时留言评论,thanks。
2. 暴力匹配算法假设现在我们面临这样一个问题:有一个文本串S,和一个模式串P,现在要查找P在S中的位置,怎么查找呢?如果用暴力匹配的思路,并假设现在文本串S匹配到 i 位置,模式串P 匹配到 j 位置,则有:如果当前字符匹配成功(即S[i] == P[j]),则i++,j++,继续匹配下一个字符;如果失配(即S[i]! = P[j]),令i = i - (j - 1),j = 0。
相当于每次匹配失败时,i 回溯,j 被置为0。
理清楚了暴力匹配算法的流程及内在的逻辑,咱们可以写出暴力匹配的代码,如下:[cpp]view plaincopyprint?1.int ViolentMatch(char* s, char* p)2.{3.int sLen = strlen(s);4.int pLen = strlen(p);5.6.int i = 0;7.int j = 0;8.while (i < sLen && j < pLen)9.{10. if (s[i] == p[j])11. {12. //①如果当前字符匹配成功(即S[i] == P[j]),则i++,j++13. i++;14. j++;15. }16. else17. {18. //②如果失配(即S[i]! = P[j]),令i = i - (j - 1),j = 019. i = i - j + 1;20. j = 0;21. }22. }23. //匹配成功,返回模式串p在文本串s中的位置,否则返回-124. if (j == pLen)25. return i - j;26. else27. return -1;28.}举个例子,如果给定文本串S“BBC ABCDAB ABCDABCDABDE”,和模式串P“ABCDABD”,现在要拿模式串P去跟文本串S匹配,整个过程如下所示:1.S[0]为B,P[0]为A,不匹配,执行第②条指令:“如果失配(即S[i]! = P[j]),令i = i - (j - 1),j = 0”,S[1]跟P[0]匹配,相当于模式串要往右移动一位(i=1,j=0)2. S[1]跟P[0]还是不匹配,继续执行第②条指令:“如果失配(即S[i]! = P[j]),令i = i - (j - 1),j = 0”,S[2]跟P[0]匹配(i=2,j=0),从而模式串不断的向右移动一位(不断的执行“令i = i - (j - 1),j = 0”,i 从2变到4,j一直为0)3. 直到S[4]跟P[0]匹配成功(i=4,j=0),此时按照上面的暴力匹配算法的思路,转而执行第①条指令:“如果当前字符匹配成功(即S[i] == P[j]),则i++,j++”,可得S[i]为S[5],P[j]为P[1],即接下来S[5]跟P[1]匹配(i=5,j=1)4. S[5]跟P[1]匹配成功,继续执行第①条指令:“如果当前字符匹配成功(即S[i] == P[j]),则i++,j++”,得到S[6]跟P[2]匹配(i=6,j=2),如此进行下去5. 直到S[10]为空格字符,P[6]为字符D(i=10,j=6),因为不匹配,重新执行第②条指令:“如果失配(即S[i]! = P[j]),令i = i - (j - 1),j = 0”,相当于S[5]跟P[0]匹配(i=5,j=0)6. 至此,我们可以看到,如果按照暴力匹配算法的思路,尽管之前文本串和模式串已经分别匹配到了S[9]、P[5],但因为S[10]跟P[6]不匹配,所以文本串回溯到S[5],模式串回溯到P[0],从而让S[5]跟P[0]匹配。
K M P 算 法 详 解
KMP算法详解(转)此前一天,一位MS的朋友邀我一起去与他讨论快速排序,红黑树,字典树,B树、后缀树,包括KMP算法,唯独在讲解KMP算法的时候,言语磕磕碰碰,我想,原因有二:1、博客内的东西不常回顾,忘了不少;2、便是我对KMP算法的理解还不够彻底,自不用说讲解自如,运用自如了。
所以,特再写本篇文章。
由于此前,个人已经写过关于KMP算法的两篇文章,所以,本文名为:KMP算法之总结篇。
本文分为如下六个部分:第一部分、再次回顾普通的BF算法与KMP算法各自的时间复杂度,并两相对照各自的匹配原理;第二部分、通过我此前第二篇文章的引用,用图从头到尾详细阐述KMP算法中的next数组求法,并运用求得的next数组写出KMP算法的源码;第三部分、KMP算法的两种实现,代码实现一是根据本人关于KMP算法的第二篇文章所写,代码实现二是根据本人的关于KMP算法的第一篇文章所写;第四部分、测试,分别对第三部分的两种实现中next数组的求法进行测试,挖掘其区别之所在;第五部分、KMP完整准确源码,给出KMP算法的准确的完整源码;第六步份、一眼看出字符串的next数组各值,通过几个例子,让读者能根据字符串本身一眼判断出其next数组各值。
力求让此文彻底让读者洞穿此KMP算法,所有原理,来龙去脉,让读者搞个通通透透(注意,本文中第二部分及第三部分的代码实现一的字符串下标i从0开始计算,其它部分如第三部分的代码实现二,第五部分,和第六部分的字符串下标i 皆是从1开始的)。
第一部分、KMP算法初解1、普通字符串匹配BF算法与KMP算法的时间复杂度比较KMP算法是一种线性时间复杂的字符串匹配算法,它是对BF算法(Brute-Force,最基本的字符串匹配算法的)改进。
对于给的原始串S 和模式串P,需要从字符串S中找到字符串P出现的位置的索引。
BF算法的时间复杂度O(strlen(S) * strlen(T)),空间复杂度O(1)。
使用C语言解决字符串匹配问题的方法
使⽤C语⾔解决字符串匹配问题的⽅法最常想到的⽅法是使⽤KMP字符串匹配算法:#include <stdio.h>#include <stdlib.h>#include <string.h>int get_nextval(char *pattern, int next[]){//get the next value of the patternint i = 0, j = -1;next[0] = -1;int patlen = strlen(pattern);while ( i < patlen - 1){if ( j == -1 || pattern[i] == pattern[j]){++i;++j;if (pattern[i] != pattern[j])next[i] = j;elsenext[i] = next[j];}elsej = next[j];}return(0);}int kmpindex(char *target, char *pattern, int pos){int tari = pos, pati = 0;int tarlen = strlen(target), patlen = strlen(pattern);int *next = (int *)malloc(patlen * sizeof(int));get_nextval(pattern, next);while ( tari < tarlen && pati < patlen ){if (pati == -1 ||target[tari] == pattern[pati]){++tari;++pati;}else{pati = next[pati];}}if(next != NULL) free(next);next = NULL;if (pati == patlen)return tari - pati;elsereturn -1;}int main(){char target[50], pattern[50];printf("imput the target:\n" );scanf("%s",target);printf("imput the pattern:\n" );scanf("%s",pattern);int ans = kmpindex(target,pattern,0);if (ans == -1)printf("error\n");elseprintf("index:%d\n",ans);return 0;}练习题题⽬描述:读⼊数据string[ ],然后读⼊⼀个短字符串。
kmp算法c语言代码
kmp算法c语言代码KMP算法C语言代码KMP算法是一种字符串匹配算法,它的核心思想是利用已知信息来避免无效的比较,从而提高匹配效率。
KMP算法的实现需要用到一个next数组,它记录了模式串中每个位置之前的最长公共前后缀的长度。
下面是KMP算法的C语言代码实现:```cvoid getNext(char* pattern, int* next) {int i = 0, j = -1;next[0] = -1;while (pattern[i]) {if (j == -1 || pattern[i] == pattern[j]) {i++;j++;next[i] = j;} else {j = next[j];}}}int kmp(char* text, char* pattern) {int i = 0, j = 0;int text_len = strlen(text);int pattern_len = strlen(pattern);int* next = (int*)malloc(sizeof(int) * pattern_len); getNext(pattern, next);while (i < text_len && j < pattern_len) {if (j == -1 || text[i] == pattern[j]) {i++;j++;} else {j = next[j];}}free(next);if (j == pattern_len) {return i - j;} else {return -1;}}```在上面的代码中,getNext函数用来计算next数组,kmp函数用来进行字符串匹配。
在getNext函数中,i表示当前位置,j表示最长公共前后缀的长度。
如果当前位置和最长公共前后缀的下一个位置相等,那么最长公共前后缀的长度加1;否则,j跳到next[j]的位置。
KMP算法详解(超级详细)
KMP算法详解(超级详细)KMP算法,全称为Knuth-Morris-Pratt算法,是一种用于字符串匹配的快速算法。
它的核心思想是在匹配过程中,当出现不匹配的情况时,利用已经匹配的字符信息,避免进行重复匹配,从而提高匹配效率。
首先,我们需要了解一个重要的概念,"部分匹配值"(partialmatch table),它指的是字符串的前缀和后缀的最长的共有元素的长度。
例如,在字符串"ABCDABD"中,它的部分匹配值是[0, 0, 0, 0, 1, 2, 0]。
接下来,我们来详细了解KMP算法的实现过程:1.首先,针对模式串(被查找的字符串)进行预处理,得到部分匹配表。
-定义两个指针,i和j,分别指向模式串的开头和当前字符。
-初始化部分匹配表,将第一个元素置为0。
-在循环中,不断地根据当前指针所指向的字符,判断是否匹配。
-若匹配,则将部分匹配表的下一个元素置为当前指针位置的下一个元素的值加1,并同时将当前指针和i都自增1-若不匹配且i>0,则将i更新为部分匹配表的前一个元素的值。
-若不匹配且i=0,则将当前指针自增1-循环结束后,部分匹配表得到构建。
2.匹配过程:-定义两个指针,i和j,分别指向需要匹配的文本和模式串的开头。
-在循环中,不断地根据当前指针所指向的字符,判断是否匹配。
-若匹配,则将两个指针都自增1-若不匹配且j>0,则将j更新为部分匹配表的前一个元素的值。
-若不匹配且j=0,则将当前指针自增1-若模式串的指针j指向了最后一个字符,则说明匹配成功,返回匹配的位置。
-若循环结束仍未找到匹配的位置,则匹配失败。
总结一下,KMP算法可以分为两个步骤:预处理和匹配。
预处理的过程是构建部分匹配表,通过比较前缀和后缀的最长共有元素的长度,将这个长度记录在部分匹配表中。
匹配的过程是根据部分匹配表中的信息,来确定下一步的匹配位置,提高匹配的效率。
通过KMP算法,我们可以有效地解决字符串匹配问题,提高了匹配的效率。
KMP算法
KMP算法在传统的字符串匹配算法中,最常用的算法是朴素的模式匹配算法。
该算法的基本思想是:从主串的第一个字符开始,逐个字符地与模式串进行比较,如果发现不匹配的字符,则回溯到主串的下一个字符重新开始匹配。
这种算法的时间复杂度是O(m*n),其中m为主串的长度,n为模式串的长度。
在主串与模式串长度相等时,该算法的时间复杂度甚至会达到O(n^2)。
KMP算法的核心思想是利用模式串的信息,避免不必要的比较。
它通过预处理模式串,构建一个部分匹配表(prefix table),来提供匹配失败时的回溯位置。
这样,在匹配的过程中,只需要根据部分匹配表的内容来调整主串和模式串的位置即可。
这种优化使得KMP算法的时间复杂度降低到O(m+n)。
具体来说,KMP算法在预处理模式串时,对于模式串的每个前缀子串,求出其最长的相等的前缀和后缀的长度。
这个长度被称为部分匹配值。
例如,对于模式串"ababc",它的前缀子串有"","a","ab","aba",而其相等的后缀子串有"","c","bc","abc"。
其中,最长的相等的前缀和后缀的长度是2,因此,部分匹配值为2、在KMP算法中,这个信息会被存储在部分匹配表中,即prefix table。
当进行匹配时,如果发现匹配失败,那么根据部分匹配表中的值来进行回溯。
具体来说,如果当前字符匹配失败,那么将模式串向右移动的距离为:当前字符之前的最长相等前缀的长度-1、这样,就可以将模式串与主串对齐继续匹配。
1. 预处理模式串,求出部分匹配表(prefix table)。
2.根据部分匹配表,进行匹配操作。
3.如果匹配成功,返回匹配的位置;否则,返回匹配失败。
总之,KMP算法是一种高效的字符串匹配算法,通过预处理模式串,提供了匹配失败时的快速回溯位置。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
kmp算法c语言
KMP算法(Knuth-Morris-Pratt算法)是一种字符串匹配算法,可以在一个主文本字符串中查找一个模式字符串的出现位置。
它的优势在于,在匹配过程中不会回溯主文本字符串,而是利用已经匹配过的信息,尽量减少比较次数,提高匹配效率。
本文将介绍KMP 算法的原理、实现以及应用场景。
一、KMP算法的原理
KMP算法的核心思想是利用模式字符串中已经匹配过的信息,避免不必要的比较。
它通过构建一个部分匹配表(Partial Match Table)来实现这一目的。
部分匹配表是模式字符串中每个位置上的前缀和后缀的最长公共长度。
通过部分匹配表,KMP算法可以在匹配过程中根据已经匹配的长度,跳过一些比较,从而提高匹配效率。
二、KMP算法的实现
KMP算法的实现包括两个步骤:构建部分匹配表和匹配过程。
首先,我们需要构建部分匹配表,具体步骤如下:
1. 初始化部分匹配表的第一个元素为0;
2. 从第二个元素开始,依次计算每个位置上的最长公共长度,直到计算完整个部分匹配表。
构建部分匹配表的代码如下所示:
```c
void buildPartialMatchTable(char *pattern, int *table) {
int len = strlen(pattern);
table[0] = 0;
int i = 1, j = 0;
while (i < len) {
if (pattern[i] == pattern[j]) {
j++;
table[i] = j;
i++;
} else {
if (j > 0) {
j = table[j-1];
} else {
table[i] = 0;
i++;
}
}
}
}
```
匹配过程则是利用已经构建好的部分匹配表,在主文本字符串中查
找模式字符串的出现位置。
具体步骤如下:
1. 初始化两个指针i和j,分别指向主文本字符串和模式字符串的第一个字符;
2. 在循环中,比较主文本字符串和模式字符串当前位置上的字符,如果相等,则继续比较下一个字符;
3. 如果模式字符串已经匹配完毕,则说明找到了一个匹配的位置,记录下来并继续查找下一个位置;
4. 如果当前字符不匹配,则根据部分匹配表,移动模式字符串的指针j到合适的位置,继续匹配。
KMP算法的匹配过程代码如下所示:
```c
int kmpSearch(char *text, char *pattern) {
int n = strlen(text);
int m = strlen(pattern);
int *table = (int *) malloc(sizeof(int) * m);
buildPartialMatchT able(pattern, table);
int i = 0, j = 0;
while (i < n) {
if (text[i] == pattern[j]) {
i++;
j++;
if (j == m) {
free(table);
return i - j;
}
} else {
if (j > 0) {
j = table[j-1];
} else {
i++;
}
}
}
free(table);
return -1;
}
```
三、KMP算法的应用场景
KMP算法可以用于解决各种字符串匹配问题,特别是在大文本中查找模式字符串的场景中,由于它的高效性能,被广泛应用于文本编辑器、代码编辑器、搜索引擎等工具中。
例如,在代码编辑器中,我们经常需要查找某个特定的函数或变量
名,KMP算法可以帮助我们快速定位到目标位置。
在搜索引擎中,KMP算法可以用于实现关键字的搜索,帮助用户快速找到相关的信息。
总结:
KMP算法是一种高效的字符串匹配算法,它通过构建部分匹配表,在匹配过程中利用已经匹配的信息,避免不必要的比较,提高匹配效率。
KMP算法的实现包括构建部分匹配表和匹配过程两个步骤,可以应用于各种字符串匹配问题,特别是在大文本中查找模式字符串的场景中。
通过掌握KMP算法,我们可以更高效地解决字符串匹配问题,提高程序的执行效率。