目录
基本概念
串:零个或多个任意字符组成的有限序列
串长:注意需要计算空格长度
子串:串中任意个连续字符组成的子序列(含空串)
真子串:不包含自身的所有子串
主串:包含子串的串
字符位置:字符在序列中的序号
子串位置:子串第一个字符在主串中的位置
空格串:由一个或多个空格组成的串
不同于空串
串相等:iff两个串的长度相等并且各个对应位置上的字符都相同时
所有空串都是相等的。(长度均为,字符均为空)
单引号本身不属于串
在串的基本操作中,通常以串的整体作为操作对象,而线性表的基本操作中,大多以单个元素作为操作对象。
类型定义、存储结构及运算
串的顺序存储结构
一组地址连续的存储单元存储串值的字符序列
串的实际长度可以再预定义长度的范围内随意,超过预定义长度的串值被舍去
串长的2种表示方法:
1.以下标为0的数组分量存放串的实际长度,S[0]就存放了实际长度
2.在串值后面加入一个不计入串长的结束标记字符,如C中以'\0'表示串值的终结,但这样串长为隐含值。
#define MAXSTRLEN 255//预定义在255内定义最大串长
typedef unsigned char SString[MAXSTRLEN +1];//0号单元存放串长
#define MAXLEN 255
typedef struct
{
char ch[MAXLEN+1];//存储串的一维数组
int length;//串的当前长度
}SString;
256个空位,下标为[0]到[255],但是下标为[0]的空位不用,从下标为[1]开始存放字符数据。
类型必须为字符型。
串的链式存储结构
优点:操作方便;缺点:存储密度低
存储密度=串值所占空间/实际分配的存储(=1/5 只有一个字符时)(地址占4个,一个字符占1个)
注:地址所占字节问题:
变量所占字节由它的类型决定,如果是复杂类型如结构体所占内存必须大于等于它的所有成员所占内存之和。(为什么可能大于,那是因为有内存对齐问题)
而变量的地址所占的内存大小是确定的,一般它是一个32位的长整型,也就是说它占4个字节。
所以常用改进后的形式(下侧)。
#define CHUNKSIZE 80 //块的大小
typedef struct Chunk
{
char ch[CHUNKSIZE];//每个块可以放多个字符
struct Chunk *next;
}Chunk;
typedef struct
{
Chunk *head, *tail;//串的头指针和尾指针
int curlen;//串的当前长度
}LString;//字符串的块链结构
串用顺序存储结构更方便,下面都是基于顺序存储结构进行操作
串的模式匹配算法
BF算法(简单匹配算法)
穷举法思想
注意有用下标从[1]开始
对回溯:i=i-j+2的理解:
(j-1)表示i,j移动了多少;i-(j-1)=i-j+1表示i退回到原来位置;i-j+2表示i到原来位置的下一个位置。
对返回:i-t.length 的理解:
i当前在s串后一位,t.length是t串长,返回对比前的位置
总体思路:
int Index BF(SString S, SString T)
{
int i=1,j=1;
while(i<=S.length && j<=T.length)//j>T.length则T中字符都被匹配成功
{
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;
}
时间复杂度:
回溯指针是BF时间复杂度高主要原因
KMP算法
改进思路:每当一趟匹配过程中出现字符比较不等时,不需要回溯 i指针,而是利用已经得到的“部分匹配”的结果将模式向右“滑动”尽可能远的一段距离后,继续进行比较。
时间复杂度提高到O(m+n)。
关键在于求主串中第i个字符(i指针不回溯)与模式中哪个字符再比较 :
大致思路 next[j]:第j个字符匹配不上,则在模式串中第1到第(j-1)个位置上的字符从两头开始比对,长度逐渐延长,找到能够匹配上的字符的长度(两端的最大匹配)(注意:这里只是从两端取字符串,匹配顺序都是各自串从左到右),在j不等于1且能够匹配成功的条件下,假设最大匹配长度为k-1(注意:1.两端找的字符串不能够是自身 2.不是遇到匹配不了就停止,可能左3与右3匹配不上,而左4与右4能够匹配,结束条件是匹配长度=j-1),则j回到第k个位置即可(前k-1个字符都能够匹配成功),即next[j]=k;若j=1,则next[j]=0;若j不等于1但是找不到匹配成功的情况,则next[j]=1。
注意:j回到下表为next[j]的位置;滑动的字符为 j-next[j] 个
int Index_KMP(SString S, SString T, int pos)//pos为主串中起始位置
{
int i=pos,j=1;//从主串中第i个位置往后查找匹配
while(i<=S[0] && j<=T[j])//这里字符数组的下表为0的位置存放字符长度
//注意循环条件
{
if(j==0 || S[i]==T[j])
{
i++; j++;
}
else
{
j=next[j];
}
}
if(j>T[0]) return i-T[0];//匹配成功,返回匹配成功的第一个字符位置
else return 0;
}
next函数求解:
next函数的改进