【数据结构】串详解(含统考真题)

存储结构

定长顺序存储

#define MANLAN 255
typedef struct{
	char ch[MANLAN];	//存放字符
	int length;			//串长度
}SString;

堆分配存储

typedef struct{
	char *ch;	//指向基地址
	int length;	//串长度
}HString;	//按串长分配存储区
HString S;
S.ch=(char *)malloc(MANLAN*sizeof(char));
S.length=0;

块链式存储

typedef struct StringNode{
	char ch[4];	//一个结点(块)存放多个字符
	struct StringNode * next;
}StringNode * SString;

定长顺序存储定义方便、操作简单;堆分配存储长度可变,不会浪费空间;块链式存储每个结点(快)可以存储多个字符,可以提高存储密度。

操作集

void StrAssian(SString &T,char chars[]);//赋值
int StrCompare(SString S,SString T);//比较
int StrLength(SString S);//求串长
void Concat(SString &T,SString S1,SString S2);//串联接
void SubString(SString &Sub,SString S,int pos,int len);//求子串
bool StrEmpty(SString S);//判空
int Index(SString S,SString T);//定位

以下用常用的定长顺序存储实现

赋值

//赋值操作。把串T赋值为chars
void StrAssian(SString &T,char chars[]){
	T.length=0;
	while(chars[T.length]!='\0')
		T.ch[++T.length]=chars[T.length-1];
}

比较

//比较操作。若S>T,则返回值>0;若S=T,则返回值=0;若S<T,则返回值<0。
int StrCompare(SString S,SString T){
	int len=min(S.length,T.length);
	for(int i=1;i<=len;i++){
		if(S.ch[i]==T.ch[i]) continue;
		if(S.ch[i]> T.ch[i]) return 1;
		else return -1;
	}
	if(S.length>T.length) return 1;
	else if(S.length<T.length) return -1;
	else return 0;
}

求串长

//求串长。返回串S的元素个数。
int StrLength(SString S){
	return S.length;
}

串联接

//串联接。用T返回由S1和S2联接而成的新串。
void Concat(SString &T,SString S1,SString S2){
	T.length=S1.length+S2.length;
	int i=1;
	for(;i<=S1.length;i++) T.ch[i]=S1.ch[i];
	for(;i<= T.length;i++) T.ch[i]=S2.ch[i-S1.length];
}

求子串

//求子串。用Sub返回串s的第pos个字符起长度为len的子串。
void SubString(SString &Sub,SString S,int pos,int len){
	if(pos+len>S.length) {
		Sub.length=0;
		return ;
	}
	Sub.length=len;
	for(int i=1;i<=len;i++) Sub.ch[i]=S.ch[i+pos-1];
}

判空

//判空操作。若s为空串,则返回 TRUE,否则返回FALSE。
bool StrEmpty(SString S){
	return StrLength(S)==0;
}

定位

//定位操作。若主串s中存在与串T值相同的子串,则返回它在主串s中第一次出现的位置;否则函数值为0。
int Index(SString S,SString T){
	int i=1,n=S.length,m=T.length;
	SString Sub;
	while(i<=n-m-1){
		SubString(Sub,S,i,m);
		if(StrCompare(Sub,T)!=0) i++;
		else return i;
	}
	return 0;
}

完整代码

#include<bits/stdc++.h>
using namespace std;

#define MANLAN 255
typedef struct{
	char ch[MANLAN];
	int length;
}SString;

void StrAssian(SString &T,char chars[]);//赋值
int StrCompare(SString S,SString T);//比较
int StrLength(SString S);//求串长
void Concat(SString &T,SString S1,SString S2);//串联接
void SubString(SString &Sub,SString S,int pos,int len);//求子串
bool StrEmpty(SString S);//判空
int Index(SString S,SString T);//定位

//不同的高级语言对串的基本操作集可以有不同的定义方法。在上述定义的操作中,
//串赋值StrAssian.电比较StrCompare、求串长StrLength、串联接Concat及求子串SubString
//五种操作构成串类型的最小操作子集,即这些操作不可能利用其他串操作来实现:
//反之,其他串操作(除串清除ClearString和串销毁 DestroyString外)均可在该最小操作子集上实现。

int main(){
	SString S,T,R;
	char chars1[]="bcbcdefaaa";
	char chars2[]="abcdefa";
	StrAssian(S,chars1);
	StrAssian(T,chars2);
	cout<<"S:";
	for(int i=1;i<=S.length;i++)cout<<S.ch[i];cout<<endl;
	cout<<"T:";
	for(int i=1;i<=T.length;i++)cout<<T.ch[i];cout<<endl;
	
//	if(StrCompare(S,T)>0) printf("S>T\n");
//	else if(StrCompare(S,T)<0) printf("S<T\n");
//	else printf("S=T\n");
//	
//	Concat(R,T,S);
//	cout<<"R:";
//	for(int i=1;i<=R.length;i++)cout<<R.ch[i];cout<<endl;
	
//	SubString(R,S,2,3);
//	cout<<"R:";
//	for(int i=1;i<=R.length;i++)cout<<R.ch[i];cout<<endl;
	
	printf("%d",Index(S,T));
	
}

//赋值操作。把串T赋值为chars
void StrAssian(SString &T,char chars[]){
	T.length=0;
	while(chars[T.length]!='\0')
		T.ch[++T.length]=chars[T.length-1];
}

//比较操作。若S>T,则返回值>0;若S=T,则返回值=0;若S<T,则返回值<0。
int StrCompare(SString S,SString T){
	int len=min(S.length,T.length);
	for(int i=1;i<=len;i++){
		if(S.ch[i]==T.ch[i]) continue;
		if(S.ch[i]> T.ch[i]) return 1;
		else return -1;
	}
	if(S.length>T.length) return 1;
	else if(S.length<T.length) return -1;
	else return 0;
}

//求串长。返回串S的元素个数。
int StrLength(SString S){
	return S.length;
}

//串联接。用T返回由S1和S2联接而成的新串。
void Concat(SString &T,SString S1,SString S2){
	T.length=S1.length+S2.length;
	int i=1;
	for(;i<=S1.length;i++) T.ch[i]=S1.ch[i];
	for(;i<= T.length;i++) T.ch[i]=S2.ch[i-S1.length];
}

//求子串。用Sub返回串s的第pos个字符起长度为len的子串。
void SubString(SString &Sub,SString S,int pos,int len){
	if(pos+len>S.length) {
		Sub.length=0;
		return ;
	}
	Sub.length=len;
	for(int i=1;i<=len;i++) Sub.ch[i]=S.ch[i+pos-1];
}

//判空操作。若s为空串,则返回 TRUE,否则返回FALSE。
bool StrEmpty(SString S){
	return StrLength(S)==0;
}

//定位操作。若主串s中存在与串T值相同的子串,则返回它在主串s中第一次出现的位置;否则函数值为0。
int Index(SString S,SString T){
	int i=1,n=S.length,m=T.length;
	SString Sub;
	while(i<=n-m-1){
		SubString(Sub,S,i,m);
		if(StrCompare(Sub,T)!=0) i++;
		else return i;
	}
	return 0;
}

模式串匹配

模式串匹配详解

精选习题

单项选择题

1、KMP算法的特点是在模式匹配时指示主串的指针(B).
A.不会变大 B.不会变小 C.都有可能 D.无法判断

2、设主串的长度为n,子串的长度为m,则简单的模式匹配算法时间复杂度为(C)KMP算法时间复杂度为(D).
A.O(m) B.O(n) C.O(mn) D.O(m+n)

3、已知串S=‘aaab’,其next数组值为(A)
A. 0123 B. 0112 C. 0231 D. 1211

4、串’ ababaaababaa '的 next数组值为(C)

A. 01234567899 B. 012121111212
C. 011234223456 D. 0123012322345

5、串’ ababaaababaa’的next数组为©
A. 1,0,1,2,3,4,5,6,7,8,8,8 B. -1,0,1,0,1,0,0,0,0,1,0,1
C. 1,0,0,1,2,3,1,1,2,3,4,5 D. -1,0,1,2,-1,0,1,2,1,1,2,3

6、串’ababaaababaa’的nextval数组为(C).
A. 0,1,0,1,1,2,0,1,0,1,0,2 B. 0,1,0,1,1,4,1,1,0,1,0,2
C. 0,1,0,1,0,4,2,1,0,1,0,4 D. 0,1,1,1,0,2,1,1,0,1,0,4

7、【2015统考真题】已知字符串S为’ abaabaabacacaabaabcc’,模式串t为’abaabc’.采用KMP算法进行匹配,第一次出现“失配”(s[i]≠t[j])时,i=j=5,则下次开始匹配时,i和j的值分别是(C).
A. i=1,j=0 B. i=5,j=0 C . i=5,j=2 D. i=6,j=2
8、【2019统考真题】设主串T=‘abaabaabcabaabc’,模式串S = ‘abaabc’,采用 KMP算法进行模式匹配,到匹配成功时为止,在匹配过程中进行的单个字符间的比较次数是(B).
A. 9 B. 10 C. 12 D. 15

综合应用题

1.在字符串模式匹配的KMP算法中,求模式的next 数组值的定义如下:
n e x t [ j ] = { 0 , j = 1 m a x { k ∣ < 1 k < j 且 ′ p 1 … p k − 1 ′ = ′ p j − k + 1 … p j − 1 ′ } , 此 集 合 不 为 空 时 1 , 其 他 情 况 next[j]=\left\{\begin{matrix}0,&j=1 \\max\{k|<1k<j且'p_1…p_{k-1}'='p_{j-k+1}…p_{j-1}'\},&此集合不为空时 \\1,&其他情况 \end{matrix}\right. next[j]=0,max{k<1k<jp1pk1=pjk+1pj1},1,j=1

1)当1j=1时,为什么要取next[1J=0?
2)为什么要取max{k},k最大是多少?
3)其他情况是什么情况,为什么取next[j]=1?

2.设有字符串S=‘aabaabaabaac’,P-’ aabaac’.

1)求出P的 next数组.
2)若S作主串,P作模式串,试给出KMP算法的匹配过程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

温柔说给风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值