数据结构---串

考纲【字符串匹配模式】

串的定义和实现

串的定义

串(string)是由零个或多个字符组成的有限序列,一般记为

S=‘a₁a₂...aₙ’(n≥0)

        aᵢ可以是字母,数字,或者其他字符;串中字符个数称为串的长度。n=0时,称为空串,用空集表示。串中任意多个连续的字符组成的子序列称为该串的子串,包含子串的串称为主串。

串的基本操作

bool StrAssign(String& T, String chars);//赋值
bool StrCopy(String& T, String S);//复制
bool StrEmpty(String T);//判空
bool StrCompare(String T, String S);//串比较
int  StrLength(String T);//求串长
bool SubString(String& Sub, String S, int pos, int len);//求子串
bool Concat(String& T, String S1, String S2);//串链接
int Index(String T,String S);//定位,定位主串S中存在与T串值相同的子串并记录第一次出现的位置
bool ClearString(String& S);//清空
bool DestoryString(String& S);//销毁

串的存储结构

#define MaxLen 255
typedef struct String //定长顺序存储
{
	char ch[MaxLen];
	int length; 
}SString;
typedef struct HString //堆分配存储
{
	char *ch;
	int length;
}H_String;

在C语言中,存在一个称为堆的自由存储区,并用malloc()和free()函数来完成动态存储管理,C++中使用new和delete也是在堆内存上。

块链的存储表示

        类似于线性表的链式存储结构,也可采用链表的方式存储串值。由于串的特殊性,具体实现每个结点既可以存放一个字符,也可以存放多个字符。每个结点称为,整个链表称为块链结构


串的模式匹配

简单的模式匹配算法

 模式匹配是指在主串找到与模式串相同的子串,并返回其位置。下列采用定长顺序存储结构

int Index(String S, String T)//定位,定位主串S中存在与T串值相同的子串并记录第一次出现的位置
{
	int i = 1, j = 1;
	while (i <= S.length && j <= T.length)
	{
		if (S.ch[i] == T.ch[j])
		{
			++i; ++j;  //继续比较
		}
		else
		{
			i = i - j + 2; j = 1; //指针后退 重新开始匹配
		}
	}
	if (j > T.length) return i - T.length;
	else return 0;
}

模式串‘abcac'和主串匹配过程:       i   j

第一趟:a b a d c a b c a c b a b

            a b c

第二趟: a b a d c a b c a c b a b

                a 

第三趟: a b a d c a b c a c b a b

                   a b c a c

第四趟: a b a d c a b c a c b a b

                      a

第五趟: a b a d c a b c a c b a b

                         a

第六趟: a b a d c a b c a c b a b

                            a b c a c j

算法思想:从主串S的第一个字符起,与模式串T的第一个字符比较,若相等,则继续逐个比较后续字符;否则从主串的下一个字符起,在重新和模式串T比较;

最坏时间复杂度O(nm)

串的模式匹配算法——KMP算法

1.KMP算法的原理

  • 'a'的前缀和后缀都为空集,最长相等前后缀长度为0
  • 'ab'的前缀为{a},后缀为{b},{a}∩{b} = Ø,最长相等前后缀长度为0
  • 'aba'的前缀为{a,ab},后缀为{ba,a},{a,ab}∩{ba,a} ={a},最长相等前后缀长度为1
  • 'abab'前缀{a,ab,aba},后缀{b,ab,bab},最长交集{ab},长度为2
  • 'ababa'前缀{a,ba,aba,abab},后缀{a,ba,aba,baba},最长交集{aba},长度3

因此,模式串'ababa'的部分匹配值为00123

2.next数组手动算法

在实际的匹配过程中,模式串在内存中是不会滑动的,发生变化的是指针,上面是手动模拟KMP算法过程;next[j]数组的含义是当模式串的第j个字符失配时,跳到next[j]位置继续比较。

编号12345
Sabcac
next01112

上述KMP算法的举例中,都假设串的编号是从1开始的;若串的编号从0开始,则next数组需要整体减1

3.next数组的推理公式

0j=1
next[j]max{k|1<k<j且'p....pₖ₋₁'='pⱼ₋ₖ....p₋₁'}当此集合不为空时
1其它情况

4.KMP算法的实现

void get_next(SString T, int next[])
{
	int i = 1, j = 0;
	next[1] = 0;
	while (i < T.length)
	{
		if (j == 0 || T.ch[i] == T.ch[j])
		{
			++i; ++j;
			next[i] = j;//若pi = pj,则next[j+1] = next[j]+1
		}
		else
			j = next[j]; //否则 j = next[j] 循环继续
	}
}
int Index_KMP(SString S, SString T, int next[])
{
	int i = 1, j = 1;
	while (i < S.length && j <= T.length)
	{
		if (j == 0 || S.ch[i] == T.ch[j])
		{
			++i; ++j; //继续比较后续字符
		}
		else
			j = next[j];  //模式串向右滑动
	}
	if (j > T.length)
		return i - T.length; //匹配成功
	else
		return 0;
}

KMP算法时间复杂度O(n+m)

KMP算法的进一步优化

void get_nextval(SString T, int nextval[])
{
	int i = 1, j = 0;
	nextval[1] = 0;
	while (i < T.length)
	{
		if (T.ch[i] == T.ch[j] || j == 0)
		{
			++i; ++j;
			if (T.ch[i] != T.ch[j]) nextval[i] = j;
			else  nextval[i] = nextval[j];
		}
		else
			j = nextval[j];
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值