串的逻辑结构与线性表极为相似,区别仅在于串的数据对象约束为字符集。
线性表操作对象大多是单个元素,而在串中一般都是以整体(字串)来作为操作对象
串的操作、实现和线性表很多不同。
串的基本操作类型不同的高级语言可以有不同的定义方法。
串赋值,串复制,比较,求长度,连接,求子串,串清除,串销毁
定长顺序存储表示
堆分配存储表示
块链存储表示
kmp算法解决了指针回溯的问题,让主串的指针不再回溯,只有模式串回溯
kmp算法的时间复杂度可以达到O(m+n)
时间复杂度按最坏的情况来算
求next函数本身是一个递推的过程
前面符合条件的最大子串
定长顺序存储表示
- 串的实际长度可在最大长度范围内任意设定,超过了定义的最大长度的部分会被舍去,称之为 截断。
- 表示串长的两种方式:
a. 在0号单元存放实时串长(下面的代码采用此种方式)
b. 串结尾加上 ‘\0’
代码实现:
#define MAXSTRLEN 255
//最大串长
typedef unsigned char SString[MAXSTRLEN + 1]
// 0号单元存放串的长度,255
// 0,1,2,3,...,255
1、串连接函数
主要运算是字符序列的复制。
此时需要考虑三种情况,判断是否需要截断。
Status Concat( SString &T,SString S1,SString S2)
{
if( S1[0] + S2[0] <= MAXSTRLEN )
//两个加起来都没超过最大长度
{
for( int i = 1;i <= S1[0];i++ )
{
T[i] = S1[i];
}
for( int i = 1,i <= S2[0];i++ )
{
T[i+S1[0]] = S2[i];
}
T[0] = S1[0] + S2[0];
}
else if( S1[0] < T[0] )
//超过了部分,但能完全覆盖第一个串
{
for( int i = 1;i <= S1[0];i++ )
{
T[i] = S1[i];
}
for( int i = 1;i <= MAXSTRLEN - S1[0];i++ )
{
T[i+S1[0]] = S2[i];
}
T[0] = MAXSTRLEN;
}
else
//第一个就超过了
{
for( int i = 1;i <= MAXSTRLEN;i++ )
{
T[i] = S1[i];
}
T[0] = MAXSTRLEN;
}
return OK;
}
2、求子串
SubString( & Sub , S , pos , len )
将串 S 中从第 pos 个字符开始,长度为 len 的字符串序列复制到 Sub 中。
难点是判断输入参数是否正确。
Status SubString( SString &Sub,SString S,int pos,int len )
{
if( pos<1 || pos>S[0] || len<0 || pos+len>S[0]+1 )
{
return ERROR;
}
Sub[1 ... len] = S[pos ... (pos + len - 1)];
Sub[0] = len;
return OK;
}