strstr函数的介绍,BF算法、KMP算法模拟实现strstr函数(含对KMP算法的详细解读)

【C语言】strstr函数刨析-----字符串查找 strstr函数是在一个字符串中查找另一个字符串的第一次出现,并返回该位置的指针,如果找不到,则返回NULL。 阅读详情

在前面的文章里,我已经介绍完了部分的字符串函数,接下来我将介绍另外一个字符串函数,并分别用两个算法来模拟实现该函数。



strstr函数

strstr函数是在一个字符串中寻找另外一个字符串的函数,我们来了解该函数的返回类型和参数类型.
请添加图片描述
在msdn查询可以得知,strstr函数的返回类型和参数类型是:char* strstr(const char* str1,const char* str2)。(在这里我们只考虑返回类型和参数类型,不关注参数名字)那么,我们继续往下寻找,查看strstr函数的返回值。
请添加图片描述
经过查询可以到,strstr函数的返回值有三种情况(为了方便理解,我先假设strstr函数查询strCharSet字符串是否存在于string字符串)。
1.如果strCharSet可以在string字符串查找到,便返回StrCharSet在string第一次出现的指针。
2.如果strCharSet没有出现在string字符串,那么就返回NULL。
3.如果strCharSet是一个长度为零的字符串(即char arr[] = "";),那么就返回string字符串。

接下来,我来举一个strstr函数的使用例子。

#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "bcd";
	char* ret = strstr(arr1,arr2);
	if(*ret != NULL)
	{
	    printf("%s\n",ret);
	}
	else
	{
	    printf("找不到\n");
	}
    return 0;
}

运行结果如下:
请添加图片描述
接下来,我来验证一下strCharSet字符串在string字符串中多次出现,返回的是第一次出现的指针位置。

#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[20] = "abcdefabcdef";
	char arr2[] = "bcde";
	char* ret = strstr(arr1,arr2);
	printf("%s\n",ret);
    return 0;
}

运行结果如下:
请添加图片描述
在该程序中的string字符串是abcdefabcdef,strCharSet字符串是bcde,如果返回第二次出现的指针,那么strstr函数返回的是第二个b的地址,自然打印bcdef。如果返回第一次出现的指针,那么strstr函数返回第一个b的地址,自然打印bcdefabcdef,由运行结果可知,strstr函数返回的是strCharSet字符串第一次出现在string字符串的位置。



BF算法

BF算法是一个比较简单的算法,但是效率却不是很高。在模拟实现strstr函数的过程中,先采用BF算法来实现strstr函数,再采用KMP算法来实现strstr函数,形成了一个从简单到困难的学习思路,有利于我们加强对strstr函数、BF算法、KMP算法的理解。

现在我来介绍一下,BF算法的思路,我依然假设我要查找strCharSet字符串是否存在于string字符串。
请添加图片描述
如上图,我要查找strCharSet字符串是否存在于string字符串,BF算法中先设置一个指针指向string字符串的第一个元素,设置另外一个指针指向strCharSet字符串的第一个元素。(假设每个小方框都存储着一个字符)

接下来,我将str1指向的元素和str2指向的元素进行比较,如果str1指向的元素和str2指向的元素是相同的,那么str1和str2都会向下走一步,比较下一个str1指向的元素和str2指向的元素是否相等。

假设现在两个元素相等,则str1和str2开始向下走一步。
请添加图片描述
那么继续比较str1指向的元素和str2指向的元素,如果str2走完strCharSet字符串时,str1指向的元素和str2指向的元素都一直相等,那么表明strCharSet字符串存在于string字符串。

如果str2在strCharset字符串走的过程中,str1指向的元素和str2指向的元素不相等,那么str1将退到string字符串相应的元素位置(第一次查询的是从string字符串的第一个元素开始的,如果匹配失败,str1回到第二个元素开始匹配;如果,str1开始从第二个元素开始匹配的,也是匹配一半的strCharSet字符串就失败,那么str1就回到第三个元素),而str2将退到str2CharSet的第一个元素。

如果感觉理解起来有点吃力,没关系,我画图带你们理解。
请添加图片描述
在第一次查询中,str1指向string字符串的第一个元素,str2指向strCharSet的第二个元素,接着str1指向的元素和str2指向的元素进行比较。由于str1指向的元素和str2指向的元素是相等的,那么str1和str2都向后面走一步。
请添加图片描述
str1指向的元素和str2指向的元素依然是相等的,那么str1和str2还是向后面走一步。
请添加图片描述
str1指向的元素和str2指向的元素依然相等的,str1和str2继续向后面走一步。
请添加图片描述
接着比较str1指向的元素和str2指向的元素,两者不相同。故开始第二次查询,str1回到string字符串的第二个元素,str2回到strCharSet字符串的第一个元素。
请添加图片描述
比较str1指向的元素和str2指向的元素,两个元素不相等,第二次查询结束,开始第三次查询。str1指向string字符串的第三个元素,str2指向strCharSet的一个元素。
请添加图片描述
就这样执行下去,直到在某一次查询中能够在string字符串查询到整个strCharSet字符串,那么就返回该次查询中str1的开始指向位置,如果查询完到string字符串,还是没有遇到这种情况,那么直接返回NULL。

记下来,我用BF算法的代码实现strstr函数。

#include<stdio.h>
#include<assert.h>
char* my_strstr(const char* str1,const char* str2)
{
	const char* s1 = str1;
	const char* s2 = str2;
	const char* p = str1;
    assert(str1 != NULL);
	if(*str2 == '\0')
	{
		return (char*)str1;
	}
	while(*p)
	{
	    s1 = p;
		s2 = str2;
		while(*s1 != '\0' && *s2 != '\0' && *s1 == *s2)
		{
		    s1++;
			s2++;
		}
		if(*s2 == '\0')
		{
	        return (char*)p;
		}
		p++;
	}
	return NULL;
}
int main()
{
	char arr1[] = "abcdefabcdef";
	char arr2[] = "bcde";
	char* ret = my_strstr(arr1,arr2);
	if(ret == NULL)
	{
	    printf("%s\n",ret);
	}
	else
	{
        printf("%s\n",ret);	
	}
    return 0;
}

请添加图片描述
由运行结果可以得知,该模拟实现strstr函数能够满足我们的要求。



KMP算法

KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人们称它为克努特—莫里斯—普拉特操作(简称KMP算法)。KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是通过一个next()函数实现,函数本身包含了模串的局部匹配信息。KMP算法的时间复杂度O(m+n) [1] 。 来自-------百度百科。

KMP算法和BF算法唯一不相同的地方在,主串str1是不会后退的,并且str2也不会回到0号位置。

接下来,我来逐步介绍KMP算法。

1.为什么主串不用后退?
主串不后退的原因是主串在后退的过程中,有时候不能匹配完全,所以KMP算法选择直接不同后退。如下:
请添加图片描述
假设在第一次排序中,str1来到了主串的下标为2的位置,而str2来到了子串下标为2的元素,此时两者不相同。那么按照BF算法的要求,str1要回到第二个元素,而str2要直接回到子串下标为0的位置,但是在KMP算法中看来,就算str1来到第二个元素也就是主串下标为1的位置,str2来到子串下标为0的位置,两者也是不相等的。请添加图片描述
所以在kMP算法中,str1直接不后退,str2回到相应的位置。
2.str2回退的位置。
请添加图片描述
str1和str2分别指向主串和子串的字符,开始依次比较主串和子串里面的元素。
请添加图片描述
主串的元素和子串的元素一直相等,直到比较到主串和子串的下标为5的元素,两个元素才不相等。按照KMP算法,str1就不再后退,str2就要后退到特定的位置。

那么,str2回退到子串的哪个元素呢?
请添加图片描述
观察主串和子串可以得知,ab这两个连续字符出现的频率很高,子串中的3号位置的ab与主串的1号位置的ab匹配一小段成功后出现了失败,所以子串中的3号位置的ab两个字符开始与主串的2号位置的ab两个字符开始比较,那么str2只需要回到子串中的下标为2的元素。(因为子串的3号位置和主串的2号位置是相同的,只需要查询子串后面的元素是否相等,所以str2回到子串中下标为2的元素。)

那么现在怎么让str2每次都知道自己要回到哪个元素呢?这个就要引出next数组。

3.引出next数组
KMP算法的精髓就是next数组:也就是用next[str2] = k来表示,不同的str2对应一个k值,这个k就是将来str2匹配不成功时,str2要移动到的位置。
k值的求解规律:

1、规则:找到匹配成功部分的两个相等的真子串(不包含本身),一个以下标 0 字符开始,另一个以 str2-1 下标字符结尾。
2、不管什么数据 next[0] = -1;next[1] = 0;(有的解释是next数组第一个元素是0,第二个元素是1,但是我们这里不这样,如果要更换的话,等到求出next数组所有元素再全部加一即可);

如:对子串为”ababcabcdabcde”的字符数组, 求其的 next 数组。
请添加图片描述
我先画出该字符数组和next数组,接下来依次求出next数组的每一个元素。
请添加图片描述
由k的求值规律2可以得知,next[0] = -1,next[1] = 0,所以,直接在next数组上面写上这两个值。

接下来,我来求next[2]的k值(str2指向子串下标为2的元素)。
请添加图片描述
由求k值的规律1可以得知,我必须找两个相等的真子串,一个必须以下标为0开始,另一个要以str2-1下标结束。

在上面求next[2]的k值时,我来寻找两个相同的字符串,一个是以下标为0开头也就是a,另一个是以下标为为str2-1也就是1结束也就是b,显然,不存在着两个相同的字符串,所以next[2] = 0;
请添加图片描述
接下来,我来求next数组的下标为3的元素(str2指向子串下标为3的元素)。
请添加图片描述
我依然要找两个相等的真子串,一个要以下标为0也就是a开始,另一个要以下标为str2-1也就是下标为2的a元素结束,那么这两个串分别是a与a。长度为1,所以next[3] = 1。
请添加图片描述
接下来,我继续求next[4]的k值(str2指向子串下标为4的元素)。
请添加图片描述
我依然要找到两个相等的真子串,一个要以下标为0的元素也就是a开始,另外一个要以下标为str2-1也就是b结束,那么,这两个真子串分别是ab和ab,长度为2,所以next[4] = 2。
请添加图片描述

按照这样计算下去,这个next数组的所有元素如下:
请添加图片描述
接下来,我来举另一个求next数组的典型例子。
在”abcabcabcabcdabcde”的子串下,求其的 next 数组?
请添加图片描述
按照前一个讲解求next数组的方法,我们可以求到了next数组下标6的元素,接下来,我来求next[7]的元素(str2指向子串下标为7的元素)。
请添加图片描述
我依然要找出两个相同的真子串,一个要以下标为0的元素也就是a开始,另外一个要以下标为str2-1的元素也就是a结束,那么这两个真子串分别是abca和abcd,如图:
请添加图片描述
在这里会不会有人在疑惑,为什么下标为3的a元素既存在于第一个真子串,又存在于第二个真子串。我们要注意的是这两个真子串中,第一个真子串是不是以下标为0的元素也就是a开始的,另一个真子串是不是以下标为str2-1,也就是a结束的,答案是肯定的,那么这个就满足了我们求k值的规则,所以下标为3的a元素既存在于第一个真子串,又存在于第二个真子串,是不影响的,所以next[7] = 4。

请添加图片描述

接下来,我来求next[8]的值(str2指向子串下标为8的元素)。
请添加图片描述
我依然要找到子串的两个真子串,一个要以下标为0的元素也就是a开头,另外一个要以下标为str2-1的元素也就是b结束,那么这两个真子串分别是abcab、abcab。
请添加图片描述
那么,next[8] = 5。在下标为3到下标为4的ab既存在于第一个真子串,又存在于第二个真子串的原因,前面已经有提到过。

请添加图片描述

接下来,我来求next[9]的值(str2指向下标为9的元素)。

请添加图片描述
我依然要找到两个子串中的两个真子串,一个要以下标为0的元素也就是a开始,另外一个要以下标为str2-1的元素也就是c结束,那么在不细心的情况下,我们可能会这样找:
请添加图片描述
第一个真子串是abc,以下标为0的元素也就是a开始,第二个真子串是abc,以下标为8的元素也就是c结束,并且子串的长度为3,所以next[9] = 3。

如果这样求,那就是错误了。
下面才是正确求法:
请添加图片描述
第一个真子串是以下标为0的元素也就是a开始的,第二个元素是以下标为str2-1的元素结束的,并且真子串长度为6,与上面的长度为3的真子串相比,我们肯定要的是真子串长度为6的,所以next[9] = 6。
请添加图片描述
按照这几种方法求下去,next数组的所有元素为:
请添加图片描述直到现在,next数组的求解基本方法和特殊案例我都已经讲解了。

4.探讨p[i]与p[i+1]的k值关系
仔细观察前面所求的next数组的元素可以得知,如果next数组的元素是有递增的情况话,那么每一个的元素都是上一个的元素加一,那么这里面是否可以引出一个简便求next数组的元素的方法呢?

假设在next[i] = k的前提下,p[0]…p[k-1] = p[x]…p[i-1](即p字符数组中,下标为0的位置到下标为k-1的位置的字符串与下标为x的位置到下标为i-1的位置的字符串相同)。如下图:
请添加图片描述

上面p字符串中的next数组元素都已经被求出,在i是8的情况下,next[i] = next[8] = 3 。由next数组中next[i] = k的公式可以得知,p字符串中下标为8的k值是3,所以我分别标出了i的位置、i-1的位置、k的位置、k-1的位置。

现在已经满足了next[i] = k的情况下,我来解释p[0]…p[k-1] = p[x]…p[i-1]。

请添加图片描述
我找出p字符数组中的下标为0的位置,到下标为k-1的位置的字符串,也就是abc。接下来就是下标为x的位置到下标为i-1的位置,i-1的位置前面早已经确定了,那么x的位置呢?观察可以发现,当x是5的时候,下标为x的位置到下标为i-1的位置的字符串与前面的abc字符串相同。
请添加图片描述
则在next[i] = k的前提下,p[0]…p[k-1] = p[x]…p[i-1]。

x的值可以被推导。
请添加图片描述
我们依然选择这个字符串来讲解。由图片可以得知,p[0]…p[2]的字符串与p[5]…p[7]的字符串长度相等,所以k-1-0 = i-1-x,则x = i - k。

总结:在next[i] = k的前提下,p[0]…p[k-1] = p[i-k]…p[i-1]。

如果p[i] == p[k]时,那么p[0]…p[k] = p[i-k]…p[i]。
如图:
请添加图片描述
我还是举上面那个例子,p[i] = p[k] = a,满足条件。
请添加图片描述
由图片的绿色标记可以得知,p[0]…p[k] = p[i-k]…p[i],x已经在前面可以证明为i-k。所以可以证明,如果p[i] == p[k]时,那么p[0]…p[k] = p[i-k]…p[i]。

现在观察i、i+1的next数组的元素,next[i+1] = next[i]+1

那么,讲了这么多,到底有什么用呢?我们可以反向推导。

当p[0]…p[k-1] = p[i-k]…p[i-1],next[i] = k。

当p[0]…p[k] = p[i-k]…p[i],所以next[i+1] = k + 1。

那么在程序实现的时候,我们就可以利用好这个规律,快速求下一个元素的next数组元素。
当p[i] != p[k]。
请添加图片描述
由图片可以得知p[i] != p[k] ,(注意,k = next[i])所以我们可以发现i+1的next数组元素为1,i的next数组元素为2,并不是i+1的next数组元素是i的next数组元素加一。

那么在这种情况,我们应该怎么求下一个next数组的元素呢?

我们采用k值回退的情况
如上图,k值现在是2,来到了p数组中下标2的位置,但是p[i] = a,p[k] = c,两者不相等,所以k值查看现在所在的p数组元素的next元素大小,为0(如图中圆圈的位置)。
请添加图片描述
所以k值回退到0的位置。
请添加图片描述
此时,p[i] = a,p[k] = a,两者相等,所以next[i+1] = k+1 = 1(注意k值已经回退到0的位置了)。

回退的特殊情况。
如果上面的k值在0的位置,p[i] 依然不等于 p[k] ,那么p要回退到-1的位置,此时就不需要再比较p[i],和p[k]了,也没办法比较,因为下标为-1对于p数组已经是越界了,直接相加,next[i+1] = k + 1 = 0。

KMP算法的代码实现。

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<assert.h>
void Getnext(int* next,const char* str2)
{
    int lenstr2 = strlen(str2);
	int i = 2;//从第二个元素开始
	int k = 0;//上一个元素的k值

	next[0] = -1;   //next数组规则
	next[1] = 0;

	while(i < lenstr2)
	{
	    if((k == -1) || (str2[i-1] == str2[k]))   //k==-1进入循环是应对k值回退的情况
		{
		    next[i] = k + 1;                   //这里比较的是i-1和i,前文介绍的是i和i+1,道理相同
			i++;
			k++;
		}
		else
		{
		    k = next[k];   //k值回退
		}
	}
}
int KMP(char* str1,char* str2,int pos)  //str1代表主串,str2代表子串,pos代表从主串pos位置开始寻找
{
    int i = pos;//主串开始的位置
	int j = 0; //子串开始的位置
	int lenstr1 = strlen(str1);
	int lenstr2 = strlen(str2);
	int* next = (int*)malloc(sizeof(int)*lenstr2);//动态开辟空间,为next数组做准备
	assert(next != NULL);//检验next数组
	Getnext(next,str2);//求next数组的元素
	while(i < lenstr1 && j < lenstr2)
	{
	    if((j == -1) || (str1[i] == str2[j])) //j等于-1进入循环是因为k值可能为-1(k后退的特殊情况)
		{
		    i++;
			j++;
		}
		else
		{
		    j = next[j];//j可能等于-1,应对方法在if语句中
		}
	}
	free(next);//释放空间
	if(j >= lenstr2)
	{
	    return i - j;
	}
	else
	{
	    return -1;
	}
}
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "cdef";
	printf("%d\n",KMP(arr1,arr2,0));
    return 0;
}

运行结果如下:
请添加图片描述
请添加图片描述
由上面的图片解析可以得知,arr2确实是从arr1下标为2开始找到,所以该程序是没有问题的。

next数组的优化
对于next数组存在着一个小缺陷,如下:
请添加图片描述
如上面的p数组中,我求出了next数组的所有元素。假设在5号位匹配失败了,那么回退到一步还是a,再退一步还是a,那么我们是否可以设计一步回退到不是相同元素的位置或者最后一个元素呢?这就要引入我们的nextval数组了。

求解nextval数组元素的规律如下:

当j = 1时,nextval[0] = -1。
当j > 1时,如果p[j] 不等于p[k],nextval[j] = next[j];如果p[j] 等于p[k],nextval[j] = nextval[k]。

按照规则,nextval数组第一个元素为-1。

请添加图片描述

当下标为1时,k值也就是next值为0,p[1] = p[0] = a,所以nextval[1] = nextval[0] = -1。

请添加图片描述

当下标为2时,k值也就是next值为1,p[2] = p[1] = a,所以nextval[2] = nextval[1] = -1。

请添加图片描述
按照这种方法,我们直接求到下标为7的元素。

请添加图片描述

当下标为8时,k值也就是next数组的值为7,p[8]等于b,p[7]等于a,两者不相等,所以nextval[8] = next[8] = 7。

请添加图片描述

nextval代码改进

void Getnextval(int* nextval,const char* str2)     //需要注意的是,该代码一直使k值等于next[i]
{
    int lenstr2 = strlen(str2);
	int i = 0;//从第一个元素开始
	int k = -1;//上一个元素的k值

	nextval[0] = -1;

	while(i < lenstr2)
	{
	    if((k == -1) || (str2[i] == str2[k]))   //k==0进入循环是应对k值回退的情况
		{                      
			i++;
			k++;                               //如果str[k]与str[i]相等,那么k加一,为后面做准备
			if(str2[i] != str2[k] && i != lenstr2)   //当i为3时,i+1为4,nextval[4]已经越界,因为nextval的下标只有0、1、2、3四个下标
			{ 
			    nextval[i] = k;                //如果p[j]不等于p[k],nextval[j] = next[j]               
			}
			else if(str2[i] == str2[k] && i != lenstr2) //当i为3时,i+1为4,nextval[4]已经越界,因为nextval的下标只有0、1、2、3四个下标
			{ 
			    nextval[i] = nextval[k];      //如果p[j]等于p[k],nextval[j] = nextval[k]。
			}
		}
		else
		{
		    k = nextval[k];   //k值回退
		}
	}
}

nextval的KMP算法全部代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<assert.h>
void Getnextval(int* nextval,const char* str2)     //需要注意的是,该代码一直使k值等于next[i]
{
    int lenstr2 = strlen(str2);
	int i = 0;//从第一个元素开始
	int k = -1;//上一个元素的k值

	nextval[0] = -1;

	while(i < lenstr2)
	{
	    if((k == -1) || (str2[i] == str2[k]))   //k==0进入循环是应对k值回退的情况
		{                      
			i++;
			k++;                               //如果str[k]与str[i]相等,那么k加一,为后面做准备
			if(str2[i] != str2[k] && i != lenstr2)   //当i为3时,i+1为4,nextval[4]已经越界,因为nextval的下标只有0、1、2、3四个下标
			{ 
			    nextval[i] = k;                //如果p[j]不等于p[k],nextval[j] = next[j]               
			}
			else if(str2[i] == str2[k] && i != lenstr2) //当i为3时,i+1为4,nextval[4]已经越界,因为nextval的下标只有0、1、2、3四个下标
			{ 
			    nextval[i] = nextval[k];      //如果p[j]等于p[k],nextval[j] = nextval[k]。
			}
		}
		else
		{
		    k = nextval[k];   //k值回退
		}
	}
}
int KMP(char* str1,char* str2,int pos)  //str1代表主串,str2代表子串,pos代表从主串pos位置开始寻找
{
    int i  = pos;//主串开始的位置
	int j = 0; //子串开始的位置
	int lenstr1 = strlen(str1);
	int lenstr2 = strlen(str2);
	int* nextval = (int*)malloc(sizeof(int)*lenstr2);//动态开辟空间,为next数组做准备
	assert(nextval != NULL);//检验next数组
	Getnextval(nextval,str2);
	while(i < lenstr1 && j < lenstr2)
	{
	    if((j == -1) || (str1[i] == str2[j])) //j等于0进入循环是因为k值可能为-1(k后退的特殊情况)
		{
		    i++;
			j++;
		}
		else
		{
		    j = nextval[j];//j可能等于-1,应对方法在if语句中
		}
	}
	free(nextval);
	if(j >= lenstr2)
	{
	    return i - j;
	}
	else
	{
	    return -1;
	}
}
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "cdef";
	printf("%d\n",KMP(arr1,arr2,0));
    return 0;
}

运行结果如下:
请添加图片描述
今天,我的strstr函数,BF算法,KMP算法已经讲完。后面的KMP算法比较困难,大家可以先收藏,慢慢理解。关注点一点,下期更精彩。

《strstr()、strtok()、strerror()》函数讲解,全网最细干货! 本文章主要详细的介绍了三个函数的操作及注意事项 阅读详情

相关推荐

KMP算法实现strstr函数

​ KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人们称它为克努特—莫里斯—普拉特操作(简称KMP算法)。KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是通过一个next()函数实现,函数本身包含了模式串的局部匹配信息。KMP算法的时间复杂度O(m+n)[1]。 ​

weixin_62560203的博客 323

strstr函数详解 看这一篇就够了-C语言(函数讲解、函数实现、使用用法举例、作用、自己实现函数 )

strstr函数详解 看这一篇就够了-C语言(函数讲解、函数实现、使用用法举例、作用、自己实现函数 )

kim的博客 10万+

C/C++ 计算程序运行的时间

C/C++计算程序执行时间的方法,精度依次增加,推荐度也依次增加 1.#include <time.h> clock_t start, finish; double process_interval ; start=clock(); process(); //要计时的程序 finish=clock(); process_interval =(double)(finish-star...

stu_shanghui的博客 1020

strstr函数详解:【子字符串查找】的利器

深入解析了strstr函数的实现原理和使用方法

天行健、君子以自强不息 1万+

01-认识脑电信号及相关信号的预处理过程

脑电信号处理过程脑电实验为什么要预处理预处理方法降采样如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入 脑电实验 本博客主要是记录基于脑电信号的情绪识别方法的研究...

脑机交流者的博客 7658

Xilinx ERNIC RoCEv2 FPGA实现与QP队列深度解析

本文深入解析Xilinx ERNIC RoCEv2在FPGA上的实现,重点剖析QP队列对的管理机制与深度优化策略。通过Verilog代码示例和工程实战,详细介绍了如何实现高吞吐量、低延迟的RDMA硬件卸载方案,为金融交易和数据中心应用提供性能优化指导。

solidity8miner的博客 877

C语言字符串函数(3)strstr,strtok函数的详解

C语言中对于strstr字符串查找子串函数、strtok字符串切割函数的讲解

weixin_69283129的博客 1万+

WSL2+Ubuntu20.04纯root环境搭建指南:告别权限烦恼的终极方案

本文提供了一份详细的WSL2+Ubuntu20.04纯root环境搭建指南,旨在为本地开发与学习打造一个免去权限干扰、极致流畅的Linux子系统环境。通过启用WSL2、安装Ubuntu 20.04,并执行核心的root用户设置,开发者可以彻底告别频繁的sudo操作,提升在文件操作、容器调试和系统配置等方面的效率。

time3的博客 474

BF算法与KMP算法得到字符串函数strstr的模拟实现

BF算法与KMP算法得到字符串函数strstr的模拟实现

2302_80442755的博客 1135

从零到一:如何用YOLOv8和PyQt5打造你的第一个花卉识别桌面应用

本文详细介绍了如何使用YOLOv8和PyQt5从零开始构建一个花卉识别桌面应用。涵盖环境搭建、数据准备、模型训练、界面设计、模型集成与性能优化等全流程,帮助开发者快速掌握深度学习目标识别技术的实际应用。

weixin_29048775的博客 453

中国IP发展之面面观

谢学军/邱善勤2006-1-25 9:29:28电子经理世界       IP远没有我们当初想象的那么简单   当SoC设计方法学刚刚传到国内的时候,学界为之欢呼雀跃,由于IP/SoC设计技术的使用,可以将发达国家用几年甚至十几年积累起来的设计技术直接为我所用,使中国的集成电路跳过漫长的积累阶段,迅速站到较高的起点上。因此在当时看来,IP/SoC设计技术是我国提升设计水平、发展

klxdmm305的专栏 1188

字符串查找 - 模拟实现strstr 、BF算法 、 KMP算法

KMP算法是一种字符串匹配算法,由D.E.Knuth.J.H.Morris和V.R.Pratt提出,因此被称为克努特-莫里斯-普拉特操作(简称KMP算法)。该算法的核心是利用匹配失败后的信息,尽量减少使用子串与主串的匹配次数,即在匹配成功得串中找与字串其前段字符匹配的串,以达到快速匹配的目的;具体实现是通过一个数组:next 数组,每次匹配失败后j 回退的下标的信息在next 数组中(此next 数组中会包含字串的局部匹配信息);想要得到数组需要通过写函数计算得到;

Distinguished_z的博客 1298

从 SAP_FLP_USER 到项目落地:把 SAP S/4HANA 中的 SAP Fiori 授权体系真正讲透

SAP Fiori授权体系涉及前端访问、应用入口和后台业务对象三层权限,仅配置基础角色如SAP_FLP_USER无法满足实际业务需求。项目实践中常见用户能看到应用磁贴但无法访问数据的问题,多因授权模型设计不完整所致。SAP建议采用分层授权策略:基础层确保launchpad访问能力,业务层配置具体应用权限。管理员角色SAP_FLP_ADMIN需结合业务权限使用,测试时可临时配置S_SERVICE=*权限,但生产环境应遵循最小权限原则。完整的授权设计需参考SAP Fiori Apps Reference Lib

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 132

【数据结构与算法】BF算法、KMP算法及OJ题

全网最详细的BF算法和KMP算法!!!🎇🎇🎇每个优秀的人都有一段沉默的时光,那段时光是付出了很多努力却得不到结果的日子,我们把它叫做扎根。🎇🎇🎇

joy.728的博客 1696

解答网友疑问:聊聊 SAP MRP 中追溯需求的技术实现

笔者到 SE37 里一查,果然有这个 Function Module,并且在里面设置断点之后,执行事务码 MD09 之后,设置在该 Function Module 内的断点也触发了,看来 ChatGPT 比较靠谱。因为红色区域的显示,是通过用户在 MD09 的 ALV 界面上双击触发的,因此我们直奔用户输入模块,PROCESS AFTER INPUT,在 check_fcode 的实现体内设置断点。通过这种追溯,企业可以了解需求和供应之间的关系,从而优化生产和采购计划,减少库存积压,提升供应链效率。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1026

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

【算法】BF、KMP算法及OJ题

【算法】BF、KMP算法以及OJ题目练习

weixin_60478154的博客 1512

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

C语言字符串函数strstr的详解使用和BF算法模拟实现

C语言字符串函数strstr的详解使用和模拟

yzc的博客 1751

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

strstr的模拟实现以及KMP算法对其优化

strstr函数就是一个在主串中寻找是否含有某个子串的 返回指向 str1 中第一次出现的 str2 的指针,如果 str2 不是 str1 的一部分,则返回空指针。 匹配过程不包括终止空字符,但它就此停止 我们来看一下思路吧 接下来看代码: char* my_strstr(const char* str1, const char* str2)//加const为了不让值改变 { assert(str1 && str2); const char* s1 = str1; const.

m0_60565784的博客 578

串的模式匹配(BF算法和KMP算法)

BF算法和KMP算法

weixin_43290957的博客 2742

库函数strstr的两种算法模拟实现(BF算法和kmp算法)

BruteForce(暴力)算法,我们的目的是查找两个字符串中一个字符串是否是另一个字符串的真子集,为了便于区分,我们把前者称为str2,后者称为str1,那么我们的目的就是就是在str1中找到字符串str2。例1假设str1[10]="abcdef";最开始的时候,str1和str2都指向字符串的首元素,对于这个例子,我们很容易想到一种方法,就是直接比较str1和str2指向的元素,当2时,str1++,str2不变,直到。...

weixin_63249832的博客 780

字符串匹配--BF算法和KMP算法

本章我们一起学习字符串匹配算法–BF算法和KMP算法的实现,希望对大家解决字符串匹配问题有些许帮助!!!🎠🎠🎠。

m0_74288306的博客 1701

数据结构 严薇敏 串 详解BF算法(BF实现strstr函数)

BF算法,即暴力(Brute Force)算法,是普通的模式匹配算法,BF算法的思想就是将目标串S的第一个字符与模式串T的第一个字符进行匹配,若相等,则继续比较S的第二个字符和 T的第二个字符;若不相等,则比较S的第二个字符和T的第一个字符,依次比较下去,直到得出最后的匹配结果。BF算法是一种蛮力算法。 ...

qq_50119037的博客 466

【数据结构与算法】之「KMP秘术」:揭开字符串匹配的神秘面纱!

在【C语言进阶技巧】探秘字符与字符串函数的奇妙世界这篇文章中,我们模拟实现了字符串查找函数strstr,但我们实现的那个办法需要主串不停的回退,当发现有不匹配的字符时,子串也得重新回退到第一个字符的位置,这样是最简单的暴力求解,它还有一个名字叫做BF算法,并且它的时间复杂度已经达到了Om∗nO(m*n)Om∗n,今天我们来介绍一种时间复杂度只有OmnO(m+n)Omn的字符串匹配算法,它就是KMP算法。

wszhj_的博客 1094

数据结构 严薇敏 串 详解KMP算法(KMP实现strstr函数)

KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人们称它为克努特—莫里斯—普拉特操作(简称KMP算法)。KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是通过一个next()函数实现,函数本身包含了模式串的局部匹配信息。 来自百度百科 ...

qq_50119037的博客 1633

实现 strStr() 函数(字符串匹配,BF,Kmp)

实现 strStr() 函数。 给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。 示例 1: 输入: haystack = “hello”, needle = “ll” 输出: 2 示例 2: 输入: haystack = “aaaaa”, needle = “bba” 输出: -1 说明: 当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。 对

little_yuan20的博客 241

LeetCode28 实现strStr()(找到子串第一次出现的位置BF,KMP)

原题目 代码分析 使用c语言strstr char *ch = strstr(haystack, needle) 得到当前位置 int strStr(char * haystack, char * needle){ char * res = strstr(haystack, needle); return res!=NULL ? res-haystack : -1; } 使用C++find int index = haystack.find(needle) 得到当前位置 class So

忘之苡巛 327
上一篇: strncpy、strncat、strncmp函数的使用说明和模拟实现
下一篇: 模拟实现通讯录的功能(静态版本)
GD_small_bit
博客等级 码龄4年 804粉丝 62原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值