【数据结构与算法】第九章:串、数组和广义表

简介: 本章将介绍串的定义和存储结构,以及重点介绍数据结构与算法中重要的串的模式匹配算法:BF和KMP。

🙊🙊作者主页:🔗求不脱发的博客

📔📔 精选专栏:🔗数据结构与算法

📋📋 精彩摘要:本章将介绍串的定义和存储结构,以及重点介绍数据结构与算法中重要的串的模式匹配算法:BF和KMP。

💞💞觉得文章还不错的话欢迎大家点赞👍➕收藏⭐️➕评论💬支持博主🤞


📚目录

📖【数据结构与算法】第九章:串、数组和广义表

📝1️⃣串的结构定义及表示

📝2️⃣串的模式匹配算法

📝3️⃣数组

📝4️⃣广义表(列表)


📖【数据结构与算法】第九章:串、数组和广义表


📝1️⃣串的结构定义及表示

定义

零个或多个字符组成的优先序列。

image.gif编辑

类型定义

ADT String
{
    数据对象;D 
    数据关系;R
    基本操作;
         (1) StrAssign (&T,chars)//串赋值
         (2) StrCompare (S,T)//串比较
         (3) StrLength (S)//求串长
         (4) Concat(&T,S1,S2)//串联     
         (5) SubString(&Sub,S,pos,len)//求子串
         (6) StrCopy(&T,S)//串拷贝
         (7) StrEmpty(S)//串判空
         (8) ClearString (&S)//清空串
         (9)  Index(S,T,pos)//子串的位置
         (11) Replace(&S,T,V)//串替换
         (12) StrInsert(&S,pos,T)//子串插入
         (12) StrDelete(&S,pos,len)//子串删除
         (13) DestroyString(&S)//串销毁
}ADT String;

image.gif

存储结构

顺序存储结构:

typedef String
{
    char *ch;//字符
    int length;//串长
}

image.gif

链式存储结构:

       链式存储结构顾名思义,将字符以块的形式,并用指针将一个个的块呈链式连接起来整体形成一个完整的串。

image.gif编辑

代码实现:

#define CHUNKSIZE 80 //可自定义块的大小
typedef struct Chunk
{
    char ch[CHUNKSIZE];
    stuct Chunk *next;
}Chunk;
typedef struct LString
{
    Chunk *head,*tail;//串的头指针和尾指针
    int curlen;//串的当前长度
}LString;

image.gif

优点:操作方便。

缺点:存储密度低。

image.gif编辑

可将多个字符存放在一个结点中,增大存储密度。image.gif编辑

📝2️⃣串的模式匹配算法

算法目的

给定一个主串和一个子串,确定主串中所含子串第一次出现的位置(定位)

算法种类

    • BF算法(又称古典的、经典的、朴素的、穷举的)
    • KMP算法(特点:速度快)

     BF算法:

    【算法设计思想】

    image.gif编辑

    Index(S,T,pos):

      1. 将主串的第pos个字符和模式的第一个字符比较,若相等,继续逐个比较后续字符;若不等,从主串的下一字符起,重新与模式的第一个字符比较。
      2. 直到主串的一个连续子串字符序列与模式相等 。返回值为S中与T匹配的子序列第一个字符的序号,即匹配成功。
      3. 否则,匹配失败,返回值 0

      【代码实现】

      int  Index(Sstring S,Sstring T,int pos){
         i=pos;
         j=1;
         while (i<=S[ 0 ] && j <=T[ 0 ]){
             if ( S[ i ]=T[ j ])
             {
                  ++i;
                  ++j; 
              }
             else
             {
                  i=i-j+2;
                  j=1;
              }
             if ( j>T[ 0 ])   return   i-T[0];
             else return 0;
          }
      }

      image.gif

      【时间复杂度】

      例: S=‘0000000001’,T=‘0001’,pos=1

      若n为主串长度,m为子串长度,最坏情况是:主串前面n-m个位置都部分匹配到子串的最后一位,即这n-m位各比较了m次 最后m位也各比较了1次。

      总次数为:(n-m)*m+m=(n-m+1)*m

      若m<<n,则时间复杂度为:O(n*m)。

      KMP算法:

      【算法设计思想】

      利用已经部分匹配的结果而加快模式串的滑动速度? 且主串S的指针i不必回溯!可提速到O(n+m)!

      image.gif编辑

      相对于BF算法,KMP算法最大的改进在于,每趟匹配过程中出现字符比较不等时,不回溯主指针i,利用已得到的“部分匹配”结果将模式向右滑动尽可能远的一段距离,继续进行比较。

      为此,定义next[j]函数,表明当模式中第j个字符与主串中相应字符“失配”时,在模式中需重新和主串中该字符进行比较的字符的位置。

      image.gif编辑

      【代码实现】

      int Index_KMP (SString S,SString T, int pos) 
      {      
             i= pos,j =1;
             while (i<S[0] && j<T[0]) {     
                   if (j==0 || S[i]==T[j]) {   i++;j++;  }
                   else 
                       j=next[j];         /*i不变,j后退*/
             }
             if (j>T[0])  return i-T[0];  /*匹配成功*/
             else   return 0;            /*返回不匹配标志*/
      }

      image.gif

      📝3️⃣数组

             本章所讨论的数组与高级语言中的数组不同之处在与,高级语言中的数组是顺序结构,而本章的数组既可以是顺序的,也可以是链式结构,用户可根据需要选择。

      抽象数据类型

      ADT Array {
          数据对象:D
          数据关系:R
          基本操作:
              (1) InitArray (&A,n,bound1, boundn)    //构造数组A
              (2) DestroyArray (&A)                     // 销毁数组A
              (3) Value(A,&e,index1,…,indexn)   //取数组元素值
              (4) Assign (A,&e,index1,…,indexn) //给数组元素赋值
      }ADT Array

      image.gif

      【一维数组】

      存储地址:LOC(0) = a,当 i > 0 时,LOC(i-1)+l = a+i*l。

      存储图示:image.gif编辑

      第i个元素存储地址:LOC(i) = LOC(i-1)+l = a+i*l。

      【二维数组】

      image.gif编辑image.gif编辑

      image.gif编辑(p = m 或 n)

      image.gif编辑 (二维数组以行序为主序)image.gif编辑

      image.gif编辑 (二维数组以行序为主序)

      image.gif编辑

      存储地址:

      设数组开始存放位置 LOC( 0, 0 ) = a , LOC ( j, k ) = a + j * m + k。

      【三维数组】

      三维数组类似二维的基础上+一维,可以按页/行/列存放,页优先的顺序存储。

      image.gif编辑

      定义一个三维数组:

      a[m1][m2] [m3] 各维元素个数为  m1, m2, m3

      image.gif

      下标为 i1, i2, i3的数组元素的存储位置:LOC ( i1, i2, i3 ) = a +  i1* m2 * m3 + i2* m3 + i3

      其中

        • i1* m2 * m3  表示: 前i1页总 元素个数
        • i2* m3          表示: 第i1页的 前i2行总元素个数
        • i3                 表示:第 i2 行前 i3 列元素个数

        除了以上基本的维度数组外,还可以将其类似的推广到 n维数组。

        各维元素个数为 m1, m2, m3, …, mn 下标为 i1, i2, i3, …, in 的数组元素的存储位置:

        image.gif编辑

        📝4️⃣广义表(列表)

        定义

        广义表(列表):n个元素组成的有限序列,(n>=0),记作 LS = (a0,a1,...an-1)。

        其中,LS为表名,ai是表元素,它可以是表(称为子表),可以是数据元素(称为原子)。n为表的长度。n=0的广义表为空表。

        广义表与线性表的区别

          • 线性表的成分都是结构上不可分的单元素。
          • 广义表的成分可以是单元素,也可以是有结构的表。
          • 线性表是一种特殊的广义表。
          • 广义表不一定是线性表,也不一定是线性结构。

          广义表的特点

            • 有次序性       一个直接前驱和一个直接后继
            • 有长度            表中元素个数
            • 有深度            表中括号的重数
            • 可递归            自己可作为自己的子表
            • 可共享            可以为其他广义表所共享
            相关文章
            |
            13天前
            |
            存储 算法 Go
            算法学习:数组 vs 链表
            算法学习:数组 vs 链表
            17 0
            |
            5天前
            |
            存储 算法 调度
            【数据结构与算法】详解循环队列:基于数组实现高效存储与访问
            【数据结构与算法】详解循环队列:基于数组实现高效存储与访问
            |
            8天前
            |
            存储 JavaScript 前端开发
            JavaScript中的数组是核心数据结构,用于存储和操作序列数据
            【6月更文挑战第22天】JavaScript中的数组是核心数据结构,用于存储和操作序列数据。创建数组可以使用字面量`[]`或`new Array()`。访问元素通过索引,如`myArray[0]`,修改同样如此。常见方法包括:`push()`添加元素至末尾,`pop()`移除末尾元素,`shift()`移除首元素,`unshift()`添加到开头,`join()`连接为字符串,`slice()`提取子数组,`splice()`进行删除、替换,`indexOf()`查找元素位置,`sort()`排序数组。还有其他如`reverse()`、`concat()`等方法。
            22 2
            |
            16天前
            |
            算法 索引 Python
            数据结构 数组部分小结
            数据结构 数组部分小结
            |
            5天前
            |
            存储 算法 编译器
            【数据结构与算法】使用数组实现栈:原理、步骤与应用
            【数据结构与算法】使用数组实现栈:原理、步骤与应用
            |
            6天前
            |
            存储 算法 Java
            Java数据结构与算法:线性数据结构之数组
            Java数据结构与算法:线性数据结构之数组
            |
            10天前
            |
            算法
            【洛谷 P1003】[NOIP2011 提高组] 铺地毯 题解(数组+贪心算法)
            **NOIP2011 提高组问题:铺地毯** 在第一象限的颁奖典礼场地,有$n$张地毯按编号顺序铺设。需找出覆盖特定点$(x, y)$的最上方地毯编号。输入包括地毯坐标和点坐标,输出地毯编号或-1表示未覆盖。 样例:给定3张地毯,点$(2,2)$被第3张地毯覆盖,输出3;另一样例点$(4,5)$未被覆盖,输出-1。 $30\%$数据$n\leq2$,$50\%$数据坐标$\leq100$,$100\%$数据$n\leq10^4$,坐标$\leq10^5$。 解决方法:从下到上遍历地毯,更新覆盖点的地毯编号。 AC代码略。
            6 0
            |
            11天前
            |
            索引
            栈的数组实现
            栈的数组实现
            6 0
            |
            3天前
            |
            搜索推荐 算法 Java
            Java数据结构与算法:排序算法之插入排序
            Java数据结构与算法:排序算法之插入排序
            |
            3天前
            |
            搜索推荐 算法 Java
            Java数据结构与算法:排序算法之冒泡排序
            Java数据结构与算法:排序算法之冒泡排序