串的定义

  • 串是由零个或多个字符组成的有限序列,也称字符串;
  • 串的表示 ‘abc’
  • 串的长度n:串中的字符数目
  • 空串 :n=0
    • 表示方法 “”,或希腊字母φ(大写)

串的数据类型

  • 对于不同的高级语言,对串的基本操作会有不同的定义方法
ADT 串(string)
Data
	串中元素仅由一个字符组成,相邻元素有前驱和后继关系
Operation
	StrAssign(T,*chars):生成一个值等于字符串常量chars的串T;
	StrCopy(T,S):串S存在,由串S复制得串T;
	ClearString(S): 串S存在,将串清空;
	StringEmpty(S):若串S为空,返回true,否则返回false;
	StringLength(S): 返回串S的个数,即串的长度;
	StrCompare(S,T):若S>T,返回值>0,若S=T,返回0,若S<T,返回值<0;
	Concat(T,S1,S2):用T返回由S1和S2联结而成的新串;
	SubString(sub,S,pos,len):用Sub返回串S的第pos个字符起长度为len的子串;
	Index(S,T,pos):若主串S存在和串T相同的子串,返回T在S中第pos个字符之后第一次出现的位置,否则返回0;
	Replace(S,T,V):用V替换所有S中出现的不重叠的T;
	StrInsert(S,pos,T):在串的第pos个字符之前插入串T;
	StrDelete(S,pos,len):从串S中删除第pos个字符起长度为len的子串

串的存储结构

  • 顺序存储结构
    • 一般是用定长数组
    • 串的长度值保存在数组的0下标位置,或者数组最后一个下标位置,或者采用结束标价字符’’\0’’
  • 堆存储结构
    • 以一组地址连续的存储单元存放串值字符序列,但它们的存储空间是在程序执行过程中动态分配而得
  • 链式存储结构
    • 和线性表相似,总体不如顺序存储灵活

朴素的模式匹配算法

  • 串的模式匹配:子串的定位
  • 目标串: 被匹配的主串
  • 模式:子串
  • 位置i称为位移,匹配成功则i为有效位移,匹配失败则i为无效位移
/*假设主串S和子串T的长度存在S[0]和T[0]中*/
/*返回T在S中第pos个字符之后的位置,若不存在,则返回0*/
/*T非空,1<=pos<=StrLength(S)*/
int Index(String S, String T, int pos)
{
	int i = pos;
	int j = 1;
	if(i>0)
	{
		while(i<=S[0]&&j<=T[0])
		{
			if (S[i]==T[j])
			{
				++i;
				++j;
			}
			else
			{
				i = i-j+2;
				j=1;
			}
			
		}
		if(j > T[0])
			return i-T[0];
		else
			return 0;
	}
}

KMP模式匹配算法

  • 基本原理:找到(如果有的话)已对比字符的重复部分(以T[1]开头的重复子串),可以减少这部分(这部分之前)的重复对比。
  • next数组用来存储子串T的当前字符要回溯的下一个位置,即第一个重复部分之后的第一个位置。
void get_next(String T, int *next)
{
	int i = 1;
	int j = 0;
	next[1]=0;
	/*++i;
	++j;
	next[i]=1;
	while(i<T[0])
	{
		/*if(T[i]==T[j])
		{
			++i;
			++j;
			next[i]=j;
		}
		else if(j==0) 如果j最终回溯到0,即无重复部分next[i]=1
		{
			++i;
			++j;
			next[i]=j;
		} */
		if(j==0||T[i]==T[j])
		{
			++i;
			++j;
			next[i]=j;
		}
		else
			j = next[j];/*如果进不了if,最终会回溯到j=0*/
	}
}
  • j=next[j]的理解:前缀 j 位置之前的值都是比较过且匹配上的,如果T[j] != T[i],那么要考虑重新比较,从哪儿开始比较好呢?肯定回溯的是 j 之前的值,而且回溯的值越大越好。所以先考虑 j 之前(前缀)有没有含T[1]的重复的部分(即 next[j]),如果有,根据 j 之前前缀后缀都匹配上了,那么后缀也有含T[1]的较短的重复片段,所以就可以接着比较T[i]和回溯值,这步的迭代就是把匹配的片段一步一步减短进行比较,如果一直匹配不上,那么j值会回溯到1,即从T[1]开始重新比较。
  • 正向理解的话就是,如果T[j] != T[i],匹配失败,就要找 i-j+1之后(后缀)出现的第一个T[1]。鉴于 j 之前的前缀和 i-j+1 后缀都匹配上了,那么找前缀的下一个T[1]位置也行;根据 next[j] 里存储的是 j之前 含 T[1] 重复片段的最大长度, 所以下一个位置就是 j-next[j]+1;再者根据 next[j] 之前是重复片段,已经比较过了,所以从next[j] 位置开始比就行。
/*返回T在S中第pos个字符之后第一次出现的位置*/
int Index_KMP(String S, String T, int pos)
{
	int i = pos;
	int j = 1;
	int next[255];
	get_next(T,next);
	while(i<=S[0]&&j<=T[0])
	{
		if(j==0||S[i]==T[j])
		{
			++i;
			++j;
		}
		else
			j = next[j];
	}
	if(j > T[0])
		return i-T[0];
	else
		return 0;
}

改进的KMP模式匹配算法

void get_nextval(String T, int *next)
{
	int i = 1;
	int j = 0;
	nextval[1]=0;
	while(i<T[0])
	{
		
		if(j==0||T[i]==T[j])
		{
			++i;
			++j;
			if(T[i]!=T[j])
				nextval[i]=j;
			else
				nextval[i]=nextval[j];
		}
		else
			j = nextva[j];
	}
}
  • 改进部分的理解:正常流程是,j值回溯后,比较T[i]和T[next[j]],但若 T[j]=T[next[j]], T[i]肯定不等于T[next[j]],就需要继续迭代回溯,所以在改进算法中加入了对这部分的判断,以减少迭代回溯的步骤。在程序中,nextval[i]=j,故需要比较的是T[i]和T[j]。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值