数据结构(C语言)3.串

1.字符串

字符串

1.定义:由零个或多个字符组成的有限序列

一般记为:s=”a1a2a3……an”(n>0)

可以是空串,可以记为“”

2.字串和主串

      例如:“over”是“lover”的字串

3.字符串的比较

      比较每个字符的ASCII值的大小,从头比到尾

      例如:“FishC”和“fishc”比较,

因为‘F’==70 ‘f’==102,’

‘f’>’F’,所以”finshc”>”FishC”

4.字符串的存储结构

      与线性表相同,分为顺序存储结构链式存储结构

      顺序存储就是用数组存储

5.BF算法

      朴素的模式匹配算法

      核心思想:看主串中是否包含子串

两个字符串的首字符比较,若相等则同时往后一位直到结束,若匹配过程字符不等则主串向前回溯到首字符的后一位,子串回到第一位,若不匹配则主串向后移一位

      效率低

6.kmp匹配

     ①优点:主串指针没有回溯,快速达到匹配状态。

        KMP是一种高效的模式匹配算法,它牺牲了一定的空间去保存next数组,提高了我们的匹配效率。

        KMP算法还能更智能的移动字符串,让字符串达到匹配效果

   

     ②公共前后缀:前面和后面一样的长度

     

A

B

A

B

                 求这个B的公共前后缀

                      因为它前面有三个元素,所以前/后缀的最多元素个数为2  此时前缀为AB 后缀BA      不相等

                        然后前缀换成A 后缀为A  相等

公共前后缀长度为1   

                第三个元素的前缀后缀只能为A B ,不相等,公共前后缀为0

                第一个A 的公共前后缀为-1

   

A

B

A

B

C

    下标      1                              2                             3

A

B

C

                 0                           1                              1(公共前后缀为0,0+1=1)

③算法

    找到不匹配位置前的公共前后缀,向后移动,使得前缀来到原来后缀的位置。如果有多对公共前后缀,取最长的公共前后缀。

     公共前缀的长度要小于字串长度

    一号位不匹配:1号位与主串下一位比较

    二号位不匹配:1号位与主串不匹配字符比较

    三号位不匹配:1号位与主串不匹配字符比较

    四号位不匹配:2号位与主串不匹配字符比较

    五号位不匹配:3号位与主串不匹配字符比较

用几号位与主串不匹配字符比较:用当前不匹配号位前的最大公共前后缀+1 ,这就是next的值

                  

         -1 0  0  1  2 3  1  1  2  3 4  5

          0 1  2  3  4 5  6  7 8  9  10 11

   下标从1开始

                                      

                           

      Next数组

      当该字符与主串字符不匹配之后,值对应的下标的字符要移动到原来不匹配的主串字符的位置。

   Next数组求法(next数组代表最大前后缀长度+1)

当新的一位与前面最大相同的字符串后一位相等时,此时为新的最大长度的最大情况,即next[j]+1

当不相等时,新的最大长度的情况为,前前最大相同字符串长度+1

以此类推,直到相等

7.BM算法从尾部开始比较

尾部不相等时,称此时的主串字符为坏字符

子串遇到坏字符的移动规则:

子串向后移:坏字符的位置-子串中上一次出现的位置

(序号从0开始)

    和子串首字符位置相对应的主串字符位置为0

    若坏字符在子串中没出现,则它在子串中出现的位置为-1

尾部相等时,继续匹配,直到中间出现不匹配情况

    此时所有匹配字符组成的字符串称为好后缀(好后缀可有多个字符)

子串遇到好后缀的移动规则:

    子串向后移:子串好后缀的位置-子串中的上一次出现的位置(没出现则为-1)

    好后缀的位置序是以最后一个字符的位置进行计算

2.BF算法实现

#include<stdio.h>
#include<stdlib.h>

typedef struct String
{
	char* data;
	int len;
}String;

//初始化
String* StringInit()
{
	String* s=(String*)malloc(sizeof(String));
	s->data=NULL;
	s->len=0;
	
	return s; 
 } 

//赋值
void StringAssign(String* s,char* data)
{
	//避免野指针 
	if(s->data)
	{
		free(s->data);
	}
	int len=0;
	char* temp=data;
	
	//计算赋值给它的字符数组的长度
	//字符数组的最后一位是|0 
	while(*temp)
	{
		len++;
		temp++;
	}
	
	//赋值给它的字符数组为空 
	if(len==0)
	{
		s->data=NULL;
		s->len=0;
	}
	else
	{
		temp=data;
		s->len=len;
		//最后一位是|0 
		s->data=(char*)malloc(sizeof(char)*(len+1));
		for(int i=0;i<len;i++,temp++)
		{
			s->data[i]=*temp;
		}
		
	}
} 


//BF算法实现 
void forceMatch(String* master,String* sub)
{
	int i=0;
	int j=0;
	
	while(i<master->len&&j<sub->len)
	{
		//首字符比较,若相等则同时往后一位直到结束
		if(master->data[i]==sub->data[j])
		{
			i++;
			j++;
		}
		else
		{
			//若匹配过程字符不等则主串向前回溯到第二位,字串回到首字符
			//若还不相等,主串再向后走一位 
			i=i-j+1;
			j=0;
		}
	}
	
	if(j==sub->len)
	{
		printf("force match succeed.\n");
	}
	else
	{
		printf("force match fail.\n");
	}
}

//打印
void StringPrint(String* s)
{
	for(int i=0;i<s->len;i++)
	{
		printf(i==0?"%c ":"->%c ",s->data[i]);
	}
	printf("\n");
}

int main()
{
	String* s=StringInit();
	String* s1=StringInit();
	
	StringAssign(s,"HELLO");
	StringAssign(s1,"fELL");
	
	StringPrint(s);
	StringPrint(s1);
	
	forceMatch(s,s1);
	
	return 0;
 } 

    3.KMPP匹配实现

#include<stdio.h>
#include<stdlib.h>

typedef struct String
{
	char* data;
	int len;
}String;

//初始化 
String* StringInit()
{
	String* s=(String*)malloc(sizeof(String));
	
	s->data=NULL;
	s->len=0;
	
	return s;
}

//赋值
void StringAssign(String* s,char* data)
{
	//避免野指针 
	if(s->data)
	{
		free(s->data);
	}
	int len=0;
	char* temp=data;
	
	//计算长度
	while(*temp)
	{
		len++;
		temp++;
	 }
	if(len==0)
	{
		s->data=NULL;
		s->len=0;
	}
	else
	{
		temp=data;
		s->len=len;
		s->data=(char*)malloc(sizeof(char)*(len+1));
		for(int i=0;i<len;i++,temp++)
		{
			s->data[i]=*temp;
		}
	}
 } 

//KMP算法实现

//获得next数组 
int* getNext(String* s)
{
	int* next=(int*)malloc(sizeof(int)*s->len);
	next[0]=-1;
	
	int i=0; //下标 
	int j=-1; //最大公共前后缀
	next[i]=j;
	
	while(i<s->len-1)
	{
		if(j==-1||s->data[i]==s->data[j])
		{
		    ++i;
		    ++j;
			next[i]=j;
		}
		else
		{
			//next[j+1]的最大值为next[j]+1 
			//当s->data[i]!=s->data[j]时,next[j+1]的可能的最大值为 next[next[j]]+1 
			//next存贮的是最大的相同字符串长度
			//当新的一位与前面最大相同的字符串后一位相等时,此时为新的最大长度的最大情况
			//即next[j]+1 
			//当不相等时,新的最大长度的情况为,前前最大相同字符串长度+1
			//以此类推,直到相等 
			j=next[j];
		}
	 } 
	return next;
}
 
//打印next数组
void printNext(int* next,int len)
{
	for(int i=0;i<len;i++)
	{
		printf("%d ",next[i]);
	}
	printf("\n");
 } 

//实现匹配
void kmpMatch(String* master,String* sub,int* next)
{
	int i=0;
	int j=0;
	while(i<master->len&&j<sub->len)
	{
		if(master->data[i]==sub->data[j])
		{
			i++;
			j++;
		}
		else
		{
			j=next[j];
		}
	}
	if(j==sub->len)
	{
		printf("kmp match succeed.\n");
	}
	else
	{
		printf("kmp match fail.\n");
	}
} 

//打印
void StringPrint(String* s)
{
	for(int i=0;i<s->len;i++)
	{
		printf(i==0?"%c ":"->%c ",s->data[i]);
	}
	printf("\n");
} 

int main()
{
	
	String* s=StringInit();
	StringAssign(s,"ababaaababaa");
	StringPrint(s);
	
	String* s1=StringInit();
	StringAssign(s1,"ababaa");
	StringPrint(s1);
	
	int* next=getNext(s1);
	printNext(next,s1->len);
	
	kmpMatch(s,s1,next);
	
	return 0;
} 

3.BM算法原理

//BM算法从尾部开始比较
//尾部不相等时,称此时的主串字符为坏字符
//子串遇到坏字符的移动规则:
//    子串向后移:坏字符的位置-子串中上一次出现的位置(序号从0开始)
//    和子串首字符位置相对应的主串字符位置为0
//    若坏字符在子串中没出现,则它在子串中出现的位置为-1
//尾部相等时,继续匹配,直到中间出现不匹配情况
//    此时所有匹配字符组成的字符串称为好后缀(好后缀可有多个字符) 
//子串遇到好后缀的移动规则:
//    子串向后移:子串好后缀的位置-子串中的上一次出现的位置(没出现则为-1) 
//    好后缀的位置序是以最后一个字符的位置进行计算 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值