【串】串的顺序存储结构

定长顺序串
1.定义:定长顺序串是将串设计成一种静态结构类型,串的存储分配是在编译时完成的。与前面所讲的线性表的顺序存储结构类似,可用一组地址连续的存储单元存储串的字符序列。
定长顺序串存储结构
#include <stdio.h>
#define MAXLEN 40 /*MAXLEN 表示串的最大长度*/
typedef struct
{
    char ch[MAXLEN]; /*ch 是存储字符串的一维数组,每个分量存储一
个字符*/
    int len;         /*len 是字符串的长度*/
} SString;
定长顺序串基本操作的实现
1. 串插入函数

【问题分析】在进行顺序串的插入时,插入位置 pos 将串分为两部分(假设为 A、 B,长度为LA、 LB)及待插入部分(假设为 C,长度为 LC),则串由插入前的 AB 变为 ACB,由于是顺序串,插入会引起元素的移动。可能出现以下三种情况:
①插入后串长( LA+LC +LB)≤ MAXLEN,则将 B 后移 LC 个元素位置,再将 C 插入。
②插入后串长>MAXLEN 且 pos+LC≤ MAXLEN,则 B 后移时会有部分字符被舍弃。
③插入后串长> MAXLEN 且 pos +LC >MAXLEN,则 B 的全部字符被舍弃(不需后移),并 且 C 在插入时也有部分字符被舍弃。
【算法描述】

StrInsert(SString *s, int pos, SString t)
/*在串 s 中下标为 pos 的字符之前插入串 t */
{
    int i;
    if (pos < 0 || pos > s->len)
        return (0); /*插入位置不合法*/
    if (s->len + t.len <= MAXLEN)
    { /*插入后串长≤MAXLEN*/
        for (i = s->len + t.len - 1; i >= t.len + pos; i--)
            s->ch[i] = s->ch[i - t.len];
        for (i = 0; i < t.len; i++)
            s->ch[i + pos] = t.ch[i];
        s->len = s->len + t.len;
    }
    else if (pos + t.len <= MAXLEN)
    { /*插入后串长>MAXLEN,但串 t 的字符序列可以全部插入*/
        for (i = MAXLEN - 1; i > t.len + pos - 1; i--)
            s->ch[i] = s->ch[i - t.len];
        for (i = 0; i < t.len; i++)
            s->ch[i + pos] = t.ch[i];
        s->len = MAXLEN;
    }
    else
    {
        /*插入后串长>MAXLEN,并且串 t 的部分字符也要舍弃*/
        for (i = 0; i < MAXLEN - pos; i++)
            s->ch[i + pos] = t.ch[i];
        s->len = MAXLEN;
    }
    return (1);
}
  • 显然,实现顺序串插入的算法其实现复杂度为: O( s->len+t.len)。
2. 串删除函数
StrDelete(SString *s, int pos, int l)
/*在串 s 中删除从下标 pos 起 l 个字符*/
{
    int i;
    if (pos < 0 || pos > (s->len - l))
        return (0); /*删除参数不合法*/
    for (i = pos + l; i < s->len; i++)
        s->ch[i - l] = s->ch[i];
    /*从 pos+l 开始至串尾依次向前移动,实现删除 l 个字符*/
    s->len = s->len - l; /*s 串长减 l*/
    return (1);
}
3. 串的简单模式匹配 Brute-Force(布鲁特-福斯)算法

【算法思想】

简单的模式匹配算法是一种带回溯的匹配算法,算法的基本思想是:从主串S 的第 pos 个字符开始,和模式串 T 的第一个字符开始比较,如果相等,就继续比较后续字符,如果不等,则从(回溯到)主串 S 的第 pos+1 个字符开始重新和模式串 T 比较,直到模式串 T 中的每一个字符和主串 S 中的一个连续字符子序列全部相等,则称匹配成功,返回和 T 中第一个字符相等的字符在主串 S 中的位置;或者主串中没有和模式串相等的字符序列,则称匹配不成功。

【算法描述】

实现时设 i、 j、 start 三个指示器:
i——指向主串 S 中当前比较的字符,起始指向 S 的首字符,此后,每比较一步,后移一步,一趟匹配失败时,回溯到该趟比较起点的下一位置。
j———指向子串 T 中当前比较的字符,起始指向 T 的首字符,此后,每比较一步,后移一步,一趟匹配失败时,回溯到 T 的首字符处。
start———记录每趟比较时在主串 S 中的起点,每趟比较后,后移一步,以便确定下一趟的起始位置。

【算法思想】

从主串s的pos位置起,与模式串t逐位匹配
①初始化:主串从pos开始,模式串从头开始
②两串逐位比较:当主串模式串均未遍历完时,对应字符作比较
若相等:主串模式串的当前比较位置均后移
若不等:主串从开始比较位置的下一个开始,模式串从头开始
③判别:若匹配成功返回起始位置,若不成功,返回-1

StrIndex(SString s, int pos, SString t)
/*求从主串 s 的下标 pos 起,串 t 第一次出现的位置,成功返回位置序号,不成功返回-1*/
{
    int i, j, start;
    if (t.len == 0)
        return (0); /* 模式串为空串时,是任意串的匹配串 */
    start = pos;
    i = start;
    j = 0; /* 主串从 pos 开始,模式串从头(0)开始 */
    while (i < s.len && j < t.len)
        if (s.ch[i] == t.ch[j])
        {
            i++;
            j++;
        } /* 当前对应字符相等时推进 */
        else
        {
            start++; /* 当前对应字符不等时回溯 */
            i = start;
            j = 0; /* 主串从 start+1 开始,模式串从头(0)开始*/
        }
    if (j >= t.len)
        return (start); /* 匹配成功时,返回匹配起始位置 */
    else
        return (-1); /* 匹配不成功时,返回-1 */
}

【算法分析】

该算法思路比较简单,但最坏时间复杂度较高,为 O( s.len* t.len),如主串为
51 个 0 ,模式串为 7 个 0 后有个 1 ,每趟都在最后一个不匹配后而倒到 start+1 ,整个匹配过程
共需 s.len- t.len=45 趟,每趟比较 t.len=8 个字符,故此例整个比较了 360 次。这个算法的主要
时间耗费在失配后的比较位置有回溯,造成了比较次数太多的情况。降低时间复杂度可采用
无回溯的算法——KMP算法
在这里插入图片描述在这里插入图片描述在这里插入图片描述

堆串

1.字符串包括串名与串值两部分,而串值采用堆串存储方法存储,串名用符号表存储。

  • 堆串存储方法:仍以一组地址连续的存储单元顺序存放串中的字符,但它们的存储空间是在程序执行过程中是动态分配的。系统将一个地址连续、容量很大的存储空间作为字符串的可用空间,每当建立一个新串时,系统就从这个空间中分配一个大小和字符串长度相同的空间存储新串的串值。
  • 串名符号表:所有串名的存储映像构成一个符号表。借助此结构可以在串名和串值之间建立一个对应关系,称为串名的存储映像。
    在这里插入图片描述
堆串存储结构
typedef struct
{
    char *ch; /*ch 域指示串的起始地址*/
    int len;  /*len 域指示串的长度*/
} HString;
堆串基本操作的实现
1. 串插入函数
StrInsert(HString *s,int pos,HString *t)
{ /*在串 s 中下标为 pos 的字符之前插入串 t */
    int i;
    char *temp;
    if (pos < 0 || pos > s->len || s->len == 0)
        return (0);                         /*插入位置不合法*/
    temp = (char *)malloc(s->len + t->len); /*动态产生足够的空间存放插入后的串*/
    if (temp == NULL)
        return (0);
    for (i = 0; i < pos; i++)
        temp[i] = s->ch[i];
    for (i = 0; i < t->len; i++)
        temp[i + pos] = t->ch[i];
    for (i = pos; i < s->len; i++)
        temp[i + t->len] = s->ch[i];
    s->len += t->len;
    free(s->ch);
    s->ch = temp;
    return (1);
}
2. 串删除函数
StrDelete(HString *s,int pos,int len)
/*在串 s 中删除从下标 pos 起 len 个字符 */
{
    int i;
    char *temp;
    if (pos < 0 || pos > (s->len - len))
        return (0); /*删除参数不合法*/
    temp = (char *)malloc(s->len - len);
    if (temp == NULL)
        return (0);
    for (i = 0; i < pos; i++)
        temp[i] = s->ch[i];
    for (i = pos; i < s->len - len; i++)
        temp[i] = s->ch[i + len];
    s->len = s->len - len;
    free(s->ch);
    s->ch = temp;
    return (1);
}
  • 1
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值