数据结构——串-顺序存储(顺序串)


串中元素逻辑关系与线性表的相同,串可以采用与线性表相同的存储结构——顺序存储结构-顺序串、链式存储结构-链串

本章从串的顺序存储结构了解串

一、串的定义

串是一种特殊的线性表,数据仅由字符组成

串是零个或多个任意字符组成的有限序列

S=“a1a2a3a4a5”(n>=0)

a1a2a3a4a5:串值
S:串名
n:串的长度
串S顺序存放示意图

二、串的相关术语

1、空串

不包含任何字符的串(串的长度n=0)

2、子串

串中任意个连续字符组成的子序列(含空串)称为该串的子串

"abcde"的子串有:“”、“a”、“ab”、“abc”、“abcd”和“abcde”等

空串是任意串的子串,任意串是自身的子串

2.1真子串

不包含自身的所有子串

3、主串

包含该子串的串称为主串

4、字符位置

字符在序列中的序号

5、模式匹配(子串位置)

子串第一个字符在主串中第一次出现的位置

6、空格串

由一个或多个空格组成的串,与空串不同

7、两个串相等

当且仅当两个串的长度相等并且各个对应位置上的字符都相等

所有空串是相等的

三、串的应用

文字编辑系统——字符串被用来表示和存储用户输入的文本数据。编译器可对这些字符串进行增删改查等操作,以实现文本的编辑功能;
信息检索系统——使用字符串来存储和查找网页内容;
数据库系统——数据库使用字符串进行排序、查找、添加、删除等操作;
语言翻译系统、通过字符串修改图片、文件路径
等等

四、串的基本操作及代码实现

相关头文件

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXLEN 255
typedef char DataType;

定义串的结构体

顺序串的结构体包含:

  1. 存储串的数组
  2. 一个整数用来存储串的长度
//结构体
typedef struct
{
  DataType ch[MAXLEN];
  int len; //长度
} SString;

串的赋值

串的赋值操作直接使用strcpy赋值,并且设置串的长度

strcpy(S->ch, "abcdef");
S->len = 6;

串的复制StrCopy(S,T)

初始条件:串S、T存在
操作结果:把串S复制在串T后面

//串的复制 串S负责在串T后面
void StrCopy(SString *S, SString *T)
{
  if (S->len + T->len >= MAXLEN)
  {
    printf("没有剩余足够的地方复制,复制失败!\n");
    return;
  }
  for (int i = 0; i < S->len; i++)
  {
    T->ch[T->len + i] = S->ch[i];
  }
  T->len += S->len;
  T->ch[T->len] = '\0';
  printf("复制完成!\n");
}

测试代码

// main函数
int main()
{
  SString *S = (SString *)malloc(sizeof(SString)); // 为S分配内存
  SString *T = (SString *)malloc(sizeof(SString)); // 为chars分配内存

  if (S == NULL || T == NULL)
  {
    // 如果分配失败,打印错误信息并退出程序
    fprintf(stderr, "Memory allocation failed\n");
    return 1;
  }
  //连接字符串
  strcpy(S->ch, "abcdef");
  S->len = 6;
  strcpy(T->ch, "123456");
  T->len = 6;
  printf("串S为:");
  DispStr(S);
  printf("串T为:");
  DispStr(T);
  //串的复制
  StrCopy(S, T);
  printf("把串S复制到串T后面,串T变为:");
  DispStr(T);
  return 0;
}

测试结果
串的复制测试结果

串的连接StrCat(S,T)

初始条件:串S和T存在
操作结果:将串T的值连接在串S后面

//串的连接
void StrCat(SString *S, SString *T)
{
  if (S->len + T->len >= MAXLEN)
  {
    printf("没有剩余足够的地方连接,连接失败!\n");
    return;
  }
  int n = S->len;
  for (int i = 0; i < T->len; i++)
  {
    S->ch[n + i] = T->ch[i];
  }
  S->len += T->len;
  S->ch[S->len] = '\0';
  printf("串连接成功!\n");
}

测试代码

// main函数
int main()
{
  SString *S = (SString *)malloc(sizeof(SString)); // 为S分配内存
  SString *T = (SString *)malloc(sizeof(SString)); // 为chars分配内存

  if (S == NULL || T == NULL)
  {
    // 如果分配失败,打印错误信息并退出程序
    fprintf(stderr, "Memory allocation failed\n");
    return 1;
  }
  //连接字符串
  strcpy(S->ch, "abcdef");
  S->len = 6;
  printf("串S为:");
  DispStr(S);
  strcpy(T->ch, "123456");
  T->len = 6;
  printf("串T为:");
  DispStr(T);
  // 串的连接
  StrCat(S, T);
  printf("把串S和串T连接后串S变为:");
  DispStr(S);
  return 0;
}

测试结果
串连接的测试结果

求子串SubString(Sub,S,pos,len)

初始条件:串S存在
操作结果:用Sub返回串S的第pos个字符起,长度为len的子串

//求子串 在串S中的起始位置position,找长度为Length的子串
void SubString(SString *S, int position, int length)
{
  if (position + length >= MAXLEN)
  {
    printf("串S中没有要找的子串\n");
    return;
  }
  for (int i = position - 1; i <= S->len - length; i++)
  {
    for (int j = 0; j < 3; j++)
    {
      printf("%c ", S->ch[i + j]);
    }
    printf("\n");
  }
}

测试代码

// main函数
int main()
{
  SString *S = (SString *)malloc(sizeof(SString)); // 为S分配内存
  SString *T = (SString *)malloc(sizeof(SString)); // 为chars分配内存

  if (S == NULL || T == NULL)
  {
    // 如果分配失败,打印错误信息并退出程序
    fprintf(stderr, "Memory allocation failed\n");
    return 1;
  }
  //连接字符串
  strcpy(S->ch, "abcdef");
  S->len = 6;
  strcpy(T->ch, "123456");
  T->len = 6;
  printf("串S为:");
  DispStr(S);
  printf("串T为:");
  DispStr(T);
  //求子串
  printf("在串S里,从第二个位置开始找长度为3的子串有:\n");
  SubString(S, 2, 3);
  return 0;
}

测试结果
求子串的测试结果

串的定位(模式匹配)StrIndex(S,T)

初始条件:串S,T都存在,T是非空串
操作结果:若串中存在与串T相同的子串,则返回串S中第一次出现的位置;否则返回-1

BF算法(Brute-Force)(简单匹配算法)——穷举法

思路:从S的每一个字符开始依次与T的字符进行匹配

BF算法匹配过程如下:
设目标串S=“aaaaab”,模式串T=“aaab”
BF算法匹配过程

int StrIndex(SString *S, SString *T)
{
  int i = 0, j = 0;
  while (i < S->len && j < T->len)
  {
    if (S->ch[i] == T->ch[j])
    {
      i++;
      j++;
    }
    else
    {
      i = i - j + 1;
      j = 0;
    }
  }
  if (j == T->len)
    return i - T->len + 1;
  else
    return -1;
}
```c
//  串的定位
int Index_BF(SString *S, SString *T)
{
  if (T->len > S->len)
  {
    printf("子串长度比原串长,不可能查得到\n");
    return -1;
  }
  for (int i = 0; i < (S->len - T->len) + 1; i++)
  {
    for (int j = 0; j < T->len; j++)
    {
      if (S->ch[i + j] != T->ch[j])
        break;
      if (j == T->len - 1 && S->ch[i + j] == T->ch[j])
        return i + 1; // 返回匹配的起始位置
    }
  }
}

```c

测试代码

// main函数
int main()
{
  SString *S = (SString *)malloc(sizeof(SString)); // 为S分配内存
  SString *T = (SString *)malloc(sizeof(SString)); // 为chars分配内存

  if (S == NULL || T == NULL)
  {
    // 如果分配失败,打印错误信息并退出程序
    fprintf(stderr, "Memory allocation failed\n");
    return 1;
  }
  //连接字符串
  strcpy(S->ch, "aaaaab");
  S->len = 6;
  strcpy(T->ch, "aaab");
  T->len = 4;
  printf("串S为:");
  DispStr(S);
  printf("串T为:");
  DispStr(T);
  //串的定位BF算法
  int n = Index_BF(S, T);
  printf("子串T在串S中的位置是:%d", n);
  return 0;
}

测试结果
串的定位(模式匹配)的测试结果

串的插入StrInsert(S,pos,T)

初始条件:串S,T都存在
操作结果:在串S的第pos个字符插入串T

//串的插入 在串S中的position位置插入T
void StrInsert(SString *S, int position, SString *T)
{
  if (S->len + T->len >= MAXLEN)
  {
    printf("超出串的最大存储,无法进行插入!\n");
    return;
  }
  for (int i = S->len; i >= position; i--)
  {
    S->ch[i + T->len] = S->ch[i];
  }
  for (int i = 0; i < T->len; i++)
  {
    S->ch[position + i] = T->ch[i];
  }
  S->len += T->len;
  printf("插入完毕\n");
}

测试代码

// main函数
int main()
{
  SString *S = (SString *)malloc(sizeof(SString)); // 为S分配内存
  SString *T = (SString *)malloc(sizeof(SString)); // 为chars分配内存

  if (S == NULL || T == NULL)
  {
    // 如果分配失败,打印错误信息并退出程序
    fprintf(stderr, "Memory allocation failed\n");
    return 1;
  }
  //连接字符串
  strcpy(S->ch, "abcdefg");
  S->len = 7;
  strcpy(T->ch, "123456");
  T->len = 6;
  printf("串S为:");
  DispStr(S);
  printf("串T为:");
  DispStr(T);

  //把串T插入到串S的position位置
  StrInsert(S, 2, T);
  printf("在串S的2号位置插入串T后串S变为:");
  DispStr(S);

  return 0;
}

测试结果
串的插入操作测试结果

串的删除StrDelete(S,pos,len)

初始条件:串S寻找
操作结果:从串S中删除第pos个字符起长度为len的子串

//串的删除 在串S的position位置删除长度为length的子串
void StrDelete(SString *S, int position, int length)
{
  for (int i = 0; i < length; i++)
  {
    S->ch[position - 1 + i] = S->ch[position - 1 + length + i];
  }
  S->len -= length;
}

测试代码

// main函数
int main()
{
  SString *S = (SString *)malloc(sizeof(SString)); // 为S分配内存
  SString *T = (SString *)malloc(sizeof(SString)); // 为chars分配内存

  if (S == NULL || T == NULL)
  {
    // 如果分配失败,打印错误信息并退出程序
    fprintf(stderr, "Memory allocation failed\n");
    return 1;
  }
  //连接字符串
  strcpy(S->ch, "abcdefg");
  S->len = 7;
  strcpy(T->ch, "123456");
  T->len = 6;
  printf("串S为:");
  DispStr(S);
  printf("串T为:");
  DispStr(T);

  //串的删除
  StrDelete(S, 3, 3);
  printf("在串S的第三个位置删除长度为3的子串后,串S变为:");
  DispStr(S);

  return 0;
}

测试结果
串的删除操作测试结果

串的替换StrReplace(S,T,V)

初始条件:串S,T和V存在,且T是非空串
操作结果:用V替换串S中出现的所有与T相等的不重叠子串

//串替换 把串S里的子串T替换为串V
void StrReplace(SString *S, SString *T, SString *V)
{
  int index = StrIndex(S, T);
  if (index != -1)
  {
    StrDelete(S, index - 1, T->len); // 删除匹配的子串T
    StrInsert(S, index - 1, V);      // 插入子串V
  }
  S->len = S->len - T->len + V->len;
  S->ch[S->len] = '\0';
}

测试代码

int main()
{
  SString S, T, V;

  strcpy(S.ch, "abcdefg");
  S.len = 7;
  strcpy(T.ch, "cde");
  T.len = 3;
  printf("串S为:");
  DispStr(&S);
  printf("串T为:");
  DispStr(&T);
  strcpy(V.ch, "456");
  V.len = 3;
  printf("串V为:");
  DispStr(&V);
  printf("把串S中的子串T替换为串V后,串S为:");
  StrReplace(&S, &T, &V);
  DispStr(&S);

  return 0;
}

测试结果
串替换的测试结果图

判断串空StrEmpty(S)

初始条件:串S存在
操作结果:若串S为空串,则返回1;否则返回0

//判断串空
int StrEmpty(SString *S)
{
  if (S->len == 0)
    return 1;
  return 0;
}

串的比较StrCompare(S,T)

初始条件:串S和T存在
操作结果:相等返回1,不等返回0;

//串的比较
int StrCompare(SString *S, SString *T)
{
  if (S->len == T->len)
  {
    for (int i = 0; i < S->len; i++)
    {
      if (S->ch[i] != T->ch[i])
        return 0;
    }
    return 1;
  }
  return 0;
}

测试代码

// main函数
int main()
{
  SString S, T, V;

  strcpy(S.ch, "cde");
  S.len = 3;
  strcpy(T.ch, "cde");
  T.len = 3;
  printf("串S为:");
  DispStr(&S);
  printf("串T为:");
  DispStr(&T);

  //串的比较
  if (StrCompare(&S, &T))
    printf("串S和串T相等\n");
  DispStr(&S);
  return 0;
}

测试结果
串比较测试结果图

串的清空StrClear(S)

初始条件:串S存在
操作结果:将串S清为空串

//串的清空
void StrClear(SString *S)
{
  S->len = 0;
  S->ch[0] = '\0'; // 设置字符串起始位置为结束符
}

输出串DispStr(S)

初始条件:串S存在
操作结果:显示串中所有字符

//输出串
void DispStr(SString *S)
{
  printf("%s \n", S->ch);
}

五、串的优缺点

缺点

  1. 存储效率低:字符串通常需要额外的存储空间来记录其长度,这可能会导致存储效率不如其他数据结构。
  2. 内存分配:在某些情况下,字符串可能需要动态内存分配,这可能会导致内存碎片和额外的内存管理开销。
  3. 性能问题:对于某些操作,如字符串拼接,如果处理不当,可能会导致性能问题,因为它们可能涉及到频繁的内存分配和复制。
  4. 不可预测的内存使用:由于字符串的长度可以变化,因此在某些情况下,它们可能导致堆栈溢出或内存泄漏。
  5. 比较效率慢:符串比较通常需要逐个字符比较,直到找到不匹配的字符或到达字符串的末尾,这可能比比较数值类型的数据结构慢。

优点

  1. 操作丰富:字符串支持大量的操作,如连接、比较、搜索、替换、插入和删除等,这些操作在编程语言的标准库中通常都有实现。
  2. 灵活性:字符串可以动态地增长和缩减,适应不同的存储需求。
  3. 简单直观:字符串是最容易理解和使用的数据结构之一。它们由字符序列组成,这与人类语言的表达方式相似,因此易于理解和操作。
  4. 应用广泛:字符串在各种应用中都是必不可少的,包括文本处理、网络通信、用户界面、数据库操作等。

本章为数据结构——串

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值