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

简介: 本章将介绍串的定义和存储结构,以及重点介绍数据结构与算法中重要的串的模式匹配算法: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的广义表为空表。

        广义表与线性表的区别

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

          广义表的特点

            • 有次序性       一个直接前驱和一个直接后继
            • 有长度            表中元素个数
            • 有深度            表中括号的重数
            • 可递归            自己可作为自己的子表
            • 可共享            可以为其他广义表所共享
            相关文章
            |
            1月前
            |
            存储 Java 程序员
            数据结构之 - 深入了解数组数据结构
            数据结构之 - 深入了解数组数据结构
            38 6
            |
            1月前
            |
            算法
            Leetcode 初级算法 --- 数组篇
            Leetcode 初级算法 --- 数组篇
            38 0
            |
            1月前
            |
            存储 算法 搜索推荐
            探索常见数据结构:数组、链表、栈、队列、树和图
            探索常见数据结构:数组、链表、栈、队列、树和图
            99 64
            |
            1月前
            |
            算法 程序员 索引
            数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
            栈的基本概念、应用场景以及如何使用数组和单链表模拟栈,并展示了如何利用栈和中缀表达式实现一个综合计算器。
            30 1
            数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
            |
            1月前
            |
            存储 算法 定位技术
            数据结构与算法学习二、稀疏数组与队列,数组模拟队列,模拟环形队列
            这篇文章主要介绍了稀疏数组和队列的概念、应用实例以及如何使用数组模拟队列和环形队列的实现方法。
            21 0
            数据结构与算法学习二、稀疏数组与队列,数组模拟队列,模拟环形队列
            |
            2月前
            |
            存储 Java
            java数据结构,线性表顺序存储(数组)的实现
            文章介绍了Java中线性表顺序存储(数组)的实现。线性表是数据结构的一种,它使用数组来实现。文章详细描述了线性表的基本操作,如增加、查找、删除、修改元素,以及其他操作如遍历、清空、求长度等。同时,提供了完整的Java代码实现,包括MyList接口和MyLinearList实现类。通过main函数的测试代码,展示了如何使用这些方法操作线性表。
            |
            3月前
            |
            存储 算法 Java
            深入算法基础二分查找数组
            文章深入学习了二分查找算法的基础,通过实战例子详细解释了算法的逻辑流程,强调了确定合法搜索边界的重要性,并提供了Java语言的代码实现。
            深入算法基础二分查找数组
            |
            3月前
            |
            算法
            【Azure Developer】完成算法第4版书中,第一节基础编码中的数组函数 histogrm()
            【Azure Developer】完成算法第4版书中,第一节基础编码中的数组函数 histogrm()
            |
            3月前
            |
            存储 Java 程序员
            "揭秘HashMap底层实现:从数组到链表,再到红黑树,掌握高效数据结构的秘密武器!"
            【8月更文挑战第21天】HashMap是Java中重要的数据结构,采用数组+链表/红黑树实现,确保高效查询与更新。构造方法初始化数组,默认容量16,负载因子0.75触发扩容。`put`操作通过计算`hashCode`定位元素,利用链表或红黑树处理冲突。`get`和`remove`操作类似地定位并返回或移除元素。JDK 1.8优化了链表转红黑树机制,提升性能。理解这些原理能帮助我们更高效地应用HashMap。
            45 0
            |
            3月前
            |
            算法
            【算法】模拟算法——外观数组(medium)
            【算法】模拟算法——外观数组(medium)