学习笔记6:串的实现和代码

前言

自己学习数据结构的笔记,看的是王道的视频,总结了串的基本概念,代码实现,以及朴素模式匹配算法和KMP算法。写了能跑的源代码,有详细的注释。希望对大家学习数据结构有所帮助。

一、串的基本概念

1.串: 零个或多个字符组成的有限序列串名

2.串的长度:串中字符的个数n

3.空串:n=0时的串;空格串:由一个或多个空格组成的串

4.子串:串中任意多个连续的字符组成的子序列称为该串的子串

5.主串:包含子串的串

6.字符在主串中的位置:某个字符在串中的序号(从1开始)

7.子串在主串中的位置:子串的第一个字符在主串中的位置

8.串是特殊的线性表,数据元素之间呈线性关系(逻辑结构相似)

二、串的基本操作

1.定义和初始化

//顺序存储定义
#define MAXLEN 255
typedef struct{
	char ch[MAXLEN];
	int length;
}SString;


//链式存储定义 
typedef struct{
	char *ch;
	int length;
}HString;


//初始化串
void InitString(HString &S){
	S.ch = (char *)malloc(MAXLEN*sizeof(char));
	S.length = 0; 
} 


//串的判空
bool StrEmpty(HString S){
	if(S.length == 0)
		return true;
	return false;		
} 

2.求串长

//求串长 
int StrLength(HString S){
	return S.length; 
} 

3.比较

//比较两个串的大小
int StrCompare(HString S,HString T){
	for(int i = 1;i<S.length && i<T.length;i++){
		if(S.ch[i] != T.ch[i])
			return S.ch[i] - T.ch[i];
	}
	
	//扫描过的所有字符都相同,则长度更长的串更大 
	return S.length - T.length; 
} 

4.复制

//串的复制
bool StrCopy(HString &T,HString S){
	T = S;
	return true; 
}

5.拼接

//字符串的拼接
bool Concat(HString &T,HString S1,HString S2){
	int i, j;
	for(i=0; i<S1.length; i++){
		T.ch[i] = S1.ch[i];
	}
	T.length = S1.length; 
	for(j=0; j<S2.length; j++){
		T.ch[T.length] = S2.ch[j];
		T.length++; 
	}
	return true;
} 

6.定位

//定位操作
int Index(HString S,HString T){
	int i = 1;
	n = strLength(S);
	m = strLength(T);
	
	HString sub;	//用于暂存子串
    InitString(sub);
	while(i<n-m+1){
		SubString(sub,S,i,m);
		if(StrCompare(Sub,T) != 0)
			i++;
		else
			return i;
	}

	//S中不存在与T相等的字串 
	return 0;
}

7.求子串

//求子串
bool SubString(HString &Sub,HString S,int pos,int len){
	
	//1.子串范围越界
	if(pos+len-1 > S.length)
		return false;
	
	//2.求子串 
	for(int i = 1;i <= len;i++){
		Sub.ch[i] = S.ch[pos+i-1];
	}
	Sub.ch[len+1] = '\0'; 
	Sub.length = len;
	return true; 
}

三、串的朴素模式匹配算法

//串的朴素模式匹配算法
int Index_BF(HString S,HString T){
	int i = 0,j = 0;	 
	while(i<S.length && j<T.length){
		if(S.ch[i] == T.ch[j]){
			i++;
			j++;
		}else{
			i = i-j+1;
			j = 0;			
		}
	}
	if(j == T.length)
		return i-T.length+1;
	else
		return -1;
} 

主串长度为n,模式串长度为m

最好时间复杂度 = O(n)

最坏时间复杂度 = O(nm)

四、KMP算法

//求模式串T的next数组
void get_next(HString 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;
			//若pi=pj,则next[j+1] = next[j]+1
			next[i] = j; 
		}else{
			//否则令j = next[j],循环继续
			j = next[j];	 
		} 
	} 
} 

//串的KMP算法
int Index_KMP(HString S,HString T){
	int i = 0,j = 0;	
	int next[T.length+1];
	get_next(T,next);
	
	//next数组优化
	int nextval[MAXLEN];
	nextval[1] = 0;
	for(int j=2;j<=T.length;j++){
		if(T.ch[next[j]] == T.ch[j])
			nextval[j] = nextval[next[j]]; 
		else
			nextval[j] = next[j]; 
	}
	  
	while(i<S.length && j<T.length){
		if(j==0 || S.ch[i] == T.ch[j]){
			i++;
			j++;		
		}else{
			j = nextval[j]; 
		}
	}
    
	if(j == T.length)
		return i - T.length + 1;
	else
		return -1;
} 

求next数组时间复杂度 = O(m)

模式匹配过程最坏时间复杂度 = O(n)

KMP算法的最坏时间复杂度 = O(m+n)

五、源代码

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

#define MAXLEN 255
//静态数组存储
typedef struct{
	char ch[MAXLEN];
	int length;
}SString;


//动态存储
typedef struct{
	char *ch;
	int length;
}HString;


//函数声明 
void InitString(HString &S);							//初始化 
bool SubString(HString &Sub,SString S,int pos,int len);	//求子串 
bool StrCopy(HString &T,HString S); 					//复制,将串S复制到T  
bool StrAssign(HString &T,char* chars); 				//赋值 
bool StrEmpty(HString S); 								//判空 
bool Concat(HString &T,HString S1,HString S2);			//拼接两个串 
void get_next(HString T,int next[]); 					//求模式串的next数组
int  StrLength(HString S); 								//求串长 
int  StrCompare(HString S,HString T); 					//比较两个串的大小 
int  Index(HString S,HString T); 						//定位 
int  Index_BF(HString S,HString T); 					//朴素模式匹配算法
int  Index_KMP(HString S,HString T); 					//KMP算法 


//主函数
int main(void) {
	HString S,T,S1,S2,S3;
	InitString(S);
	InitString(T);
	InitString(S1);
	InitString(S2);
	InitString(S3);
	char s[] ="abcdef";
	char t[] ="cde";
	char s1[] ="0";
	char s2[] ="1234";
	char s3[] ="abc";
	StrAssign(S1,s1);
	StrAssign(S2,s2);
	StrAssign(S3,s3);
	StrAssign(S,s);
	StrAssign(T,t);
	printf("S串:%s 串长为:%d\n",S.ch,StrLength(S)); 
	printf("T串:%s 串长为:%d\n",T.ch,StrLength(T));
	printf("S1串:%s 串长为:%d\n",S1.ch,StrLength(S1)); 
	printf("S2串:%s 串长为:%d\n",S2.ch,StrLength(S2));
	printf("S3串:%s 串长为:%d\n",S3.ch,StrLength(S3));
	printf("==================\n"); 
	Concat(S1,S2,S3);
	printf("将串S2和S3拼接后新串为:%s 串长为:%d\n",S1.ch,StrLength(S1));
	printf("串s2比串s3大%d\n",StrCompare(S2,S3));
	StrCopy(S1,S2); 
	printf("串S1复制为S2后串为:%s 串长为:%d\n",S1.ch,StrLength(S1));
	printf("T串在S串中的位置为:%d\n",Index(S,T));
	printf("朴素模式匹配算法求T串在S串的位置为:%d\n",Index_BF(S,T));
	printf("KMP算法求T串在S串的位置为:%d\n",Index_KMP(S,T));
    return 0;
}


//初始化串
void InitString(HString &S){
	S.ch = (char *)malloc(MAXLEN*sizeof(char));
	S.length = 0; 
} 


//求串长 
int StrLength(HString S){
	return S.length; 
} 


//串的赋值
bool StrAssign(HString &T,char *chars){
	int i;
	int len = 0;
	//c指针指向字符串首地址
	char *c = chars;
	//当c指向空,也就是遍历完chars时,退出循环  
	while(*c != NULL){		
		len++;
		//c的值加1,也就是地址值加一  
		c++;		
	} 
	//如果传入字符串为空,则将T置为空
	if(len == 0){	
		T.ch = NULL;
		T.length = 0;
		return true; 
	} else{
		//多分配一个空间给结束符
		T.ch=(char*)malloc(sizeof(char)*(len+1));
		if(T.ch == NULL)
			return false;	
		else{
			c=chars;
			//给T赋值
			for(i=0;i<=len;i++,c++){
				T.ch[i]=*c;//c是所指向的地址值,*c是指所向地址的值		 
			} 
			T.length = len;
			return true; 
		} 
	}
} 

 
//串的复制,将串S复制为T 
bool StrCopy(HString &T,HString S){
	T = S;
	return true; 
} 


//串的判空
bool StrEmpty(HString S){
	if(S.length == 0)
		return true;
	return false;		
} 


//求子串
bool SubString(HString &Sub,HString S,int pos,int len){
	
	//1.子串范围越界
	if(pos+len-1 > S.length)
		return false;
	
	//2.求子串 
	for(int i = 1;i <= len;i++){
		Sub.ch[i] = S.ch[pos+i-1];
	}
	Sub.ch[len+1] = '\0'; 
	Sub.length = len;
	return true; 
}


//比较两个串的大小
int StrCompare(HString S,HString T){
	for(int i = 1;i<S.length && i<T.length;i++){
		if(S.ch[i] != T.ch[i])
			return S.ch[i] - T.ch[i];
	}
	
	//扫描过的所有字符都相同,则长度更长的串更大 
	return S.length - T.length; 
} 


//定位操作
int Index(HString S,HString T){
	int i = 1;
 	int n = StrLength(S); 
	int m = StrLength(T);
	
	HString sub;	//用于暂存子串
	InitString(sub);
	while(i<n-m+1){
		SubString(sub,S,i,m);
		if(StrCompare(T,sub) != 0)
			i++;
		else
			return i;
	}
	//S中不存在与T相等的子串 
	return 0;
} 


//字符串的拼接
bool Concat(HString &T,HString S1,HString S2){
	int i, j;
	for(i=0; i<S1.length; i++){
		T.ch[i] = S1.ch[i];
	}
	T.length = S1.length; 
	for(j=0; j<S2.length; j++){
		T.ch[T.length] = S2.ch[j];
		T.length++; 
	}
	return true;
} 


//串的朴素模式匹配算法
int Index_BF(HString S,HString T){
	int i = 0,j = 0;	//用i扫描主串S,j扫描模式串T 
	while(i<S.length && j<T.length){
		if(S.ch[i] == T.ch[j]){
			i++;
			j++;
		}else{
			i = i-j+1;
			j = 0;			
		}
	}
	if(j == T.length)
		return i-T.length+1;
	else
		return -1;
} 

//求模式串T的next数组
void get_next(HString 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;
			//若pi=pj,则next[j+1] = next[j]+1
			next[i] = j; 
		}else{
			//否则令j = next[j],循环继续
			j = next[j];	 
		} 
	} 
} 

//串的KMP算法
int Index_KMP(HString S,HString T){
	int i = 0,j = 0;	//用i扫描主串S,j扫描模式串T 
	int next[T.length+1];
	get_next(T,next);
	
	//next数组优化
	int nextval[MAXLEN];
	nextval[1] = 0;
	for(int j=2;j<=T.length;j++){
		if(T.ch[next[j]] == T.ch[j])
			nextval[j] = nextval[next[j]]; 
		else
			nextval[j] = next[j]; 
	}
	  
	while(i<S.length && j<T.length){
		if(j==0 || S.ch[i] == T.ch[j]){
			i++;
			j++;		
		}else{
			j = nextval[j]; 
		}
	}
	if(j == T.length){ 
		return i - T.length + 1;
	} 
	else{ 
		return -1;
	} 
} 



 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值