数据结构与算法——串

串(String)

定义:零个或多个任意字符组成的有序列
请添加图片描述
特点:内容受限制的线性表,数据元素只能是字符

相关属术语:
**子串:**串中任意个连续的字符组成的子序列(含空串)
e.g.“abcde”的字串——“”、“a”、“ab”、“abcde”…
真子串:不包含自身的子串
**主串:**包含字串的串
**字符的位置:**字符在序列中的序号
**子串的位置:**子串第一个字符在主串中的位置
**空格串:**有一个或多个空格组成的串,区别于空串
< “ \t\t ” vs “” >
**串长度:**串中字符的个数
**串相等:**当且仅当串长度相等且各对应位置上的字符都相同(所有空串都相等)
串的起点是0还是1?

案例

  1. 病毒感染检测
    将人和病毒的DNA均表示成一些字母组成的字符串序列,若病毒的序列在患者的序列中出现过,则确诊。(注意:人的DNA是线性的,病毒的是环状的)
    例如:病毒BAA,患者1AAABBBA,患者2BABBBA。1感染2未感染
    方法:用baa aba aab baab aaba abaa跟患者DNA序列对比

串的类型定义、存储结构及运算

ADT String{
-数据对象:D = {ai | ai 属于 CharacterSet,i = 1,2,…,n,n>=0}
-数据关系:R1 = {<ai - 1,ai> | ai - 1,ai 属于D,i= 1,2,…,n}
-基本操作:StrAssign(&T,chars)串赋值、StrCompare(S,T)串比较、StrLength(S)求串长、Concat(&T,S1,S2)串连接、求子串、串拷贝、串判空、清空串、Index(S,T,pos)子串的位置、串替换、子串插入、子串删除、串销毁
}ADT String

存储方式
  1. 循序存储结构——顺序串
  2. 链式存储结构——链串
顺序存储

不需要额外的空间描述其地址关系
试用数组存储

#define MAXLEN 256
typedef struct{			
   char ch[MAXLEN+1];	//存储串的一维数组
   int length;			//串的当前长度
}SString;

编号[0,255],其中0闲置不用,研究算法是更加简便

与线性表的区别:数据元素类型只能是字符。

链式存储

加上直接后继的指针
优点:操作方便
缺点:存储密度(20%)较低
(存储密度 = 串值占/实际分配占)
改善方法:放多个字符在一个节点,密度提升

#define CHUNKSIZE 80
typedef struct Chunk{
	char ch[CHUNKSIZE];
	struct Chunk *next;
}Chunk;

typedef struct{
	Chunk *head,*tail;
	int curlen;
}LString;		//字符串的块链结构

一般而言,顺序存储更常用,一般只用匹配和查找的功能

串的模式匹配算法

算法目的:确定主串中所含子串(模式串)第一次出现的位置
应用:搜搜引擎、拼写检查、语言翻译、数据压缩
算法种类:

  1. BF算法:暴力破解,实现效率低
  2. KMP算法:速度快
BF算法

亦称简单匹配算法,采用穷举法思路
例如:S=“aaaaab” T=“aaab”
起点都在1
主串子串的起点都在1
在这里插入图片描述
匹配失败,i回溯,回溯位置为当前位置i,减去移动的位置j-1,加上下一个位置1.即i=i-(j-1)+1=i-j+2
在这里插入图片描述
再次进行匹配
在这里插入图片描述
失败后再次回溯
在这里插入图片描述
在这里插入图片描述
j与i依次匹配,且目前j的位置大于子串的长度,匹配成功

算法思路

Index(S,T,pos)
将主串的第pos各字符与模式串的第一个字符比较:

  1. 相等,急需逐个比较后续字符
  2. 不相等,从主串的下一个字符其,再次开始匹配
    直到主串的一个连续子串字符序列与模式串相等,返回匹配的第一个字符的序号,否则返回值0.
int index_BF(SString S,SString T,int pos){
	int i=pos,j=1;
	while(i <= S.len && j <= T.len){//匹配成功或主串匹配完就结束 
		if(S.ch[i] == T.ch[j]){		//主串与子串一次匹配 
			i++;
			j++;
		}
		else{						//回溯 
			i = i - j + 2;
		}
	}
	if(j >= T.len) return i-T.len; 	//匹配成功 
	else return 0;					//匹配失败 
}

时间复杂度:
最好情况,T(T.len)
最坏情况:T((S.len-T.len+1)T.len),O(S.lenT.len)

KMP算法

利用已经部分匹配的结果而加快模式串的滑动速度,主串i指针不再回溯,提速到O(m+n)
请添加图片描述

void get_next(SString T,int & next[]){
	int i= 1,j = 0;
	next[0] = 1;
	while(i < T.len()){
		if(j == 0 || T.ch[i] == T.ch[j]){
			++i;
			++j;
			next[i] = j;
		}
		else j = next[j];
	}
}

如果子串本身重复
T=“aaab” S=“aabaabaaaab”,改良以下

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

回溯就不那么麻烦了

int index_KMP(SString S,SString T,int pos){
	int i = pos,j = 1;
	while(i < S.len() && j < T.len()){
		if(j==0||S.ch[i)==T.ch[j]){
			i++;
			j++
		}
		else {
			j = next[j];			//
		}
	}
	if(j >= T.len) return i-T.len; 	//匹配成功 
	else return 0;					//匹配失败 
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值