串的定长顺序存储c语言,【C语言实现】定长顺序串(内有完整代码)

简书内代码已上传GitHub:点击我 去GitHub查看代码

3 / 29 更新 基本操作写了些注意的点,把一些原本模仿书上写的代码进行了修改...书太坑了(国内教材)...

941d227d2743

一串葡萄

一.顺序串及其结构定义

顺序串类似于线性表的顺序存储结构,都是用一组地址连续的存储单元存储串值。

因为是定长的顺序串,所以按照我们按照预定义的大小,为每个串变量分配固定长度的存储区,结构如下:

// 用户可在255以内定义最大串长

#define MAXSTRLEN 255

// 0号单元存放串的长度, 故长度为MAXSTRLEN + 1

typedef unsigned char SString[MAXSTRLEN + 1];

PS:这里一定要清楚typedef的用法,这样定义后,举个例子:

SString a 就等价于 char a[MAXSTRLEN + 1]

二. 顺序串的基本操作(13种)

生成串:

因为是定长串,所以需要考虑长度超限的情况

T[0]存储串长

// 生成一个值等于chars的串

Status StrAssign(SString T, char chars[]){

// 长度超限

if(strlen(chars) > MAXSTRLEN){

//printf("error: too long to assign\n");

return ERROR;

}else{

// 存放长度

T[0] = strlen(chars);

//复制

for(int i = 1 ; i <= T[0] ; ++i)

T[i] = *(chars + i - 1);

return OK;

}

}

复制串

按元素依次赋值即可

//由串S复制得到串T

Status StrCopy(SString &T, SString S){

for(int i = 0 ; i <= S[0] ; ++i){

T[i] = S[i];

}

return OK;

}

3.判断串是否为空

串的长度为0, 返回True, 长度不为0,返回False

// 判断S是否为空

Status StrEmpty(SString S){

return S[0] == 0 ? True : False;

}

比较串的大小

比较串的大小其实就是比较ASCII的大小

从前到后按元素依次比较,比如abcdefg < abddefg

S > T, 返回值 > 0, S == T , 返回值= 0, S < T, 返回值 < 0

// 比较串的大小, 如果S > T , 返回值 > 0; 如果S == T, 返回 0;如果S < T ,返回值 < 0

Status StrCompare(SString S, SString T){

int i;

for(i = 1 ; i <= S[0] && i <= T[0] ; ++i){

if(S[i] != T[i]) return S[i] - T[i];

}

return S[0] - T[0];

}

返回串的长度

返回S[0]的值,对数据进行封装

// 返回串的长度

int StrLength(SString S){

return S[0];

}

清空串

将S[0]置空,相当于对已有数据做上标记 - 空

DestroyString等同于ClearString

// 清空串

Status ClearString(SString &S){

S[0] = 0;

return OK;

}

连接两串,生成新串

分为截断和未截断两种可能性

S1 + S2 < T 则不发生截断, S1 + S2 > T 发生截断

截断还需要考虑是只有S2截断还是S1截断....

其实感觉合并成一种情况就行了,死板的学着教材还是...不大好

// 连接两串返回新串,未截断返回True,截断返回False

Status Concat(SString &T, SString S1, SString S2){

// 未截断

if(S1[0] + S2[0] <= MAXSTRLEN){

T[0] = S1[0] + S2[0];

// S1

for(int i = 1 ; i <= S1[0] ; ++i){

T[i] = S1[i];

}

// S2

for(int j = S1[0] + 1 ; j <= T[0] ; ++j){

T[j] = S2[j - S1[0]];

}

return True;

// S2截断 / 完全截断

}else if(S1[0] <= MAXSTRLEN){

T[0] = MAXSTRLEN;

// S1先赋给T

for(int i = 1 ; i <= S1[0] ; ++i){

T[i] = S1[i];

}

// S2剩余部分

for(int j = S1[0] + 1 ; j <= MAXSTRLEN ; ++j){

T[j] = S2[j - S1[0]];

}

return False;

}

/*

// S1、S2截断或者S2完全截断

}else{

T[0] = MAXSTRLEN;

// S1

for(int i = 1 ; i <= T[0] ; ++i){

T[i] = S1[i];

}

return False;

}

*/

}

用Sub返回特定子串

注意pos的越界判定

// 用Sub返回特定子串(pos开始,长度为len)

int SubString(SString &Sub, SString S, int pos, int len){

if((pos < 1) || (pos > S[0]) || (len < 0) || (len > S[0] - pos + 1))

return ERROR;

Sub[0] = len;

for(int i = pos ; i < pos + len ; ++i){

Sub[i] = S[i];

}

return OK;

}

模式匹配

还是用的Sunday算法,简单好懂,需要的移步 Sunday算法

// 返回子串在主串pos后第一次出现的位置(Sunday)

Status Index(SString S, SString T, int pos){

int len1 = S[0], len2 = T[0];

// 获得偏移量数组

int * next = (int*)malloc(sizeof(int) * len2);

for(int k = 0 ; k < len2 ; ++k){

next[k] = len2 - k;

}

int i = pos, j = 0;

while(i < len1 && j < len2){

// 依次判断,相等 i 、 j自增

if(S[i + 1] == T[j + 1]){

++i;

++j;

}else{

// 如果索引下标超出范围,结束搜索

if(i + len2 - j > len1)

break;

// 获得元素在T串中的索引(逆序第一个)

int index = -1;

for(int l = len2 - 1 ; l >= 0 ; --l){

if(S[i + len2 - j] == T[l]){

index = l;

break;

}

}

// 元素在串内,按偏移量数组进行偏移

if(index != -1){

i += (next[index] - j);

j = 0;

}else

// 不在串内,直接整体移到该元素后

i += len2 + 1 - j;

}

}

// 成功匹配

if(j == len2)

return i - len2;

return 0;

}

插入

和concat一样分为完全插入和部分插入

同样注意边界问题

// 插入

Status StrInsert(SString &S, int pos, SString T){

if( (pos < 1) || (pos > S[0] + 1) )

return ERROR;

// 完全插入

if(S[0] + T[0] <= MAXSTRLEN){

for(int i = S[0] ; i >= pos ; --i){

S[i+T[0]] = S[i];

}

for(int i = pos ; i < pos + T[0] ; ++i)

S[i] = T[i - pos + 1];

S[0] += T[0];

return True;

}else{

// 部分插入

// 若T完整插入,在T后插入剩余S

for(int i = MAXSTRLEN ; i >= pos + T[0] ; --i){

S[i] = S[i - T[0]];

}

// pos处插入T

for(int i = pos ; i < pos + T[0] && i <= MAXSTRLEN ; ++i){

S[i] = T[i - pos + 1];

}

S[0] = MAXSTRLEN;

return False;

}

}

删除

边界问题

删除后连接分离的子串

// 删除指定位置指定长度子串

Status StrDelete(SString &S, int pos, int len){

if( (pos < 1) || (pos > S[0] - len + 1) || (len < 0) )

return ERROR;

// 拼接

for(int i = pos + len ; i <= S[0] ; ++i)

S[i - len] = S[i];

// 更新长度

S[0] -= len;

return OK;

}

串的替换

简单的来说就是 定位子串,删除子串,插入子串,如此循环,直到没有能匹配的子串为止

把Replace放在插入和删除后面是由原因的,这样可以简单的利用插入和删除操作来实现replace

// 用V替换S中所有出现的T

Status Replace(SString &S, SString T, SString V) {

// 从串S的第一个字符起查找串T

int i = 1;

Status k;

// 如果T是空串 ,返回错误

if(StrEmpty(T)) return ERROR;

do{

// 保存i后第一个子串的位置

i = Index(S, T, i);

// 若找到子串

if(i) {

// 删除T

StrDelete(S, i, StrLength(T));

// 插入V

k = StrInsert(S, i, V);

// 不能完全插入

if(!k)

return ERROR;

// 查找下一个T

i += StrLength(V);

}

}while(i);

return OK;

}

13.输出

遍历,打印

// 输出字符串T。

void StrPrint(SString T) {

for( int i = 1 ; i <= T[0] ; ++i )

printf("%c ", T[i]);

printf("\n");

}

三.串的应用

文本编辑

建立词索引表

PS:未完待续

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值