第四章串、数组、广义表(4.1-4.3.2)
4.1串的定义
串(String)是由零个或者多个字符组成的有限序列,又名叫字符串。
一般记为s=“a1a2……an”(n>=0)
其中s是串的名称,用双引号括起来括起来的字符序列是串的值,引号不属于串的内容。ai(1=< i <=i)可以是字母,数字或者其他字符,i就是该字符在串中的位置。串中的字符数目n称为串的长度,定义中谈到有限是指长度n是一个有限的数值。零个字符的串称为空串(null string),它的长度为零,可以直接使用双引号表示,所谓的序列,说明串的相邻字符之间具有前驱和后继的关系。
注意:
空格串:是只包含空格的串。注意它与空串的区别,空格串的内容是有长度的,而且可以不止是一个空格。
子串与主串,串中任意个数的连续字符组成的子序列称为该串的子串,相应的,包含子串的串称为主串。
4.2案例引入
案例4.1病毒感染检验
1.案例分析
因为患者的 DNA 和病毒 DNA 均是由一些字母组成的字符串序列, 要检测某种病毒 DNA 序列是否在患者的 DNA 序列中出现过 , 实际上就是字符串的模式匹配问题。可以利用 BF 算法,也可以利用更高效的KMP算法。但与一般的模式匹配问题不同的是,此案例中病毒的 DNA 序列是环状的, 这样需要对传统的 BF 算法或KMP算法进行改进。
下面给出利用 BF 算法实现检测的方案。
2.案例实现
对于每一个待检测的任务, 假设病毒 DNA 序列的长度是 m, 因为病毒 DNA 序列是环状的 ,为了线性取到每个可行的长度为 m 的模式串,可将存储病毒DNA序列的字符串长度扩大为 2m,将病毒DNA序列连续存储两次。然后循环m次,依次取得每个长度为m的环状字符串,将此字符串作为模式串,将人的DNA序列作为主串,调用BF算法进行模式匹配。 只要匹配成功,即可中止循环,表明该人感染了对应的病毒;否则,循环m次结束循环时, 可通过BF算法的返回值判断该人是否感染了对应的病毒。
3.算法步骤
1.从文件中读取待检测的任务数 num。
2.根据 num个数依次检测每对病毒DNA和人的DNA是否匹配,循环 num次,执行以下操作:
• 从文件中分别读取一对病毒DNA序列和人的DNA序列;
• 设置一个标志性变量flag, 用来标识是否匹配成功,初始为0, 表示未匹配;
• 病毒DNA序列的长度是 m, 将存储病毒DNA序列的字符串长度扩大为 2m, 将病毒DNA序列连续存储两次;
• 循环m次,重复执行以下操作:
► 依次取得每个长度为m的病毒DNA环状字符串;
► 将此字符串作为模式串,将人的DNA序列作为主串, 调用BF算法进行模式匹配,将匹配结果返回赋值给flag;
► 若flag非0, 表示匹配成功, 中止循环,表明该人感染了对应的病毒。
• 退出循环时, 判断flag的值,若flag非0, 输出 “YES” , 否则,输出 “NO”。
4.算法描述
void Virus detection ()
{//利用 BF 算法实现病毒检测
ifstream inFile("病毒感染检测输入数据. txt");
ofstream outFile("病毒感染检测输出结果. txt");
inFile>>num; //读取待检测的任务数
while(num--) //依次检测每对病毒 DNA 和人的 DNA 是否匹配
{
inFile>>Virus.ch+1; //读取病毒 DNA 序列, 字符串从下标 1 开始存放
inFile>>Person.ch+1; //读取人的 DNA 序列
Vir=Virus.ch; //将病毒 DNA 临时暂存在Vir中,以备输出
flag=0; //用来标识是否匹配,初始为0, 匹配后为非0
m=Virus.length; //病毒 DNA 序列的长度是 m
for(i=m+1, j=l; j<=m; j++)
Virus.ch[i++]=Virus.ch[j]; //将病毒字符串的长度扩大2倍
Virus.ch[2*m+1]='\0'; //添加结束符号
for(i=0;i<m;i++) //依次取得每个长度为m 的病毒 DNA 环状字符串 temp
{
for (j=1; j<=m; j ++) temp.ch[j]=Virus.ch[i+j];
temp.ch[m+1]='\0'; //添加结束符号
flag=Index_BF (Person, temp, 1); //模式匹配
if(flag) break; //匹配即可退出循环
}// for
if (flag) outFile<<Vir+l<<" "<<Person.ch+1<<" "<<"YES"<<endl;
else outFile<<Vir+l<<" "<<Person.ch+1<<" "<<"NO"<<endl;
}//while
}
4.3串的类型定义、存储结构及其运算
4.3.1串的抽象类型定义
ADT String{
数据对象:D={ ai | ai ∈ CharacterSet,i=1,2,…,n,n≥0}
数据关系:R1={ < a(i-1),ai > | a(i-1),ai ∈ D,i=2,…,n }
基本操作:
StrAssign(&T,chars)
// 生成一个其值等于chars的串T(chars是字符串常量)
StrCopy(&T,S)
// 由串S复制得T
StrEmpty(S)
// 若S为空串,返回true,否则返回false
StrCompare(S,T)
// 若S>T,则返回值>0;若S=T,则返回值=0;若S<T,则返回值<0
StrLength(S)
// 返回S的元素个数,称为串的长度
ClearString(&S)
// 将S清为空串
Concat(&T,S1,S2)
// 用T返回由S1和S2联接而成的新串
SubString(&Sub,S,pos,len)
// 用Sub返回串S的第pos个字符起长度为len的子串
Index(S,T,pos)
// 若主串S中存在和串T值相同的子串,则返回它在主串S中第pos个字符之后第一次出现的位置;否则函数值为0
Replace(&S,T,V)
// 用V替换主串S中出现的所有与T相等的不重叠的子串
StrInsert(&S,pos,T)
// 在串S的第pos个字符之前插入串T
StrDelete(&S,pos,len)
// 从串S中删除第pos个字符起长度为len的子串
DestroyString(&S)
// 销毁串S
}ADT String
4.3.2串的存储结构
串中元素逻辑关系与线性表的相同,串可以采用与线性表相同的存储结构。
1.串的顺序存储
串的定长顺序存储结构,可以简单地理解为采用 “固定长度的顺序存储结构” 来存储字符串,因此限定了其底层实现只能使用静态数组。使用定长顺序存储结构存储字符串时,需结合目标字符串的长度,预先申请足够大的内存空间。
//------串的定长顺序存储结构-------
#define MAXLEN 255 //串的最大长度
typedef struct{
char ch[MAXLEN+1]; //存储串的一维数组
int length; //串的当前长度
}SString;
2.串的链式存储
串的块链存储,指的是使用链表结构存储字符串。
优点:操作方便
缺点:存储密度较低
为克服缺点,可以将多个字符存放在一个结点里
//-------串的链式存储结构---------
#define CHUNKSIZE 80 //可由用户定义的块大小
typedef struct Chunk{
char ch[CHUNKSIZE];
struct Chunk*next;
}Chunk;
typedef struct{
Chunk *head,*tail; //串的头和尾指针
int length; //串的当前长度
}LString; //字符串的块链结构
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具