顺序存储结构的线性表

article/2025/9/23 7:22:05

1.0. 什么是线性表?

所谓线性,即一条线,这条线可以是直线,也可以是曲线。

1. 顺序存储结构的线性表

所谓,肯定都不陌生,生活中有各种各样的表或者表格。我们在表格中填写各种各样的信息,通过表格,能够很好地对信息进行分类储存和分析。

表的特点有:

    • 表由若干单元格组成
    • 单元格之间有顺序
    • 除特殊位置的单元格(首起和结尾)有一个“邻居”外,其他单元格都有两个“邻居”。
    • 1. 顺序存储结构的线性表

      那么什么是线性表呢?简单来说,就是使用“直线”或“曲线”连接起来的表。

      1. 顺序存储结构的线性表

      明确几个名词:

      • 我们在表中称呼的“单元格”,在线性表中可以称之为元素
      • 对于某个元素,在其前邻的元素称之为直接前驱元素,在其后邻的元素称之为直接后继元素
      • 线性表中元素的个数称之为线性表的长度
      • 第一个元素称之为首元素,最后一个元素称之为尾元素
      • 由上图可以总结出线性表的特点:

        • 线性表由若干元素组成,用来存储信息。
        • 元素之间有顺序。
        • 除了首元素(只有一个直接后继元素)和尾元素(只有一个直接前驱元素)外,其它元素都有且仅有一个直接前驱元素和一个直接后继元素。简单来说,即元素之间只能由一对一的关系。
        • 总结一下,线性表是由若干元素按线性结构(一对一的关系)组成的有限序列。

          1.1. 线性表的顺序存储结构

          不管数据结构的形式再怎么变,数据结构的最根本的目的始终不会变,那就是为了更高效地对数据进行存储、修改、删除和访问,这种高效通常体现在时间上和空间上,也即程序运算速度快慢和所用存储空间的少多。

          那么线性表这种数据结构是如何进行存储的呢?前面介绍了一种“用直线连接”的线性表,“直线”只是形象化的语言,实际上的存储中是不会有所谓“直线”这种东西的。

          1. 顺序存储结构的线性表

          所谓“直线连接”即顺序存储,那么什么是顺序存储呢?

          首先得先解释一下什么是内存。内存是计算机的存储器的一种,它扮演着非常中要的角色。世上的一切东西,即使是虚拟的,也需要有物理的实体作为载体。

          举个例子,孩子们的玩耍需要有土地来承载,公园、游乐园等都是这种载体。没有土地作为载体,再活泼的孩子也没法活泼起来。对于代码来说,内存就是玩耍时需要的那块土地。

          总之,内存就是代码运行时各种信息数据的载体空间。有了内存,我们才能施展拳脚。

          1. 顺序存储结构的线性表

          既然涉及到空间,那该空间的东西肯定会以某种形式排列起来。通常来说,无外乎“整齐划一”和“杂乱无章”两种形式。

          比如,一群孩子肩并肩地站成一排,占据一定的连续土地。

          反映在内存中,就是数据紧密相接,占据一定的连续内存。

          1. 顺序存储结构的线性表

          这种“占据连续的内存空间”即为顺序存储方式。

          可以把内存比作一幢大楼,楼中有许多房间,每个房间都有房间号,一个房间刚好住一个人。当 A、B、C、D 四位小朋友来到大楼里,选了连续的 4 个房间分别入住,那么我们就可以认为,这四位小朋友是“顺序入住”的。

          内存 = 大楼,房间 = 内存单元,房间号 = 内存地址,入住的人 = 要存储的数据。

          反映在内存中,所谓顺序存储,即用一段连续的内存单元分别存储线性表中的数据。

          1. 顺序存储结构的线性表

          如上图所示,线性表的顺序存储是在内存空间中开辟一块连续的空间,开辟好之后,这块空间就被这个线性表“占用”了。

          这种顺序存储结构的线性表我们可以称之为顺序表

          1.2. 顺序表的实现思路

          线性表的每个数据元素的类型都相同、数据元素个数有限。根据这个特性我们很容易想出可以用一维数组来实现顺序存储结构

          1. 顺序存储结构的线性表

          注意:是先占用再使用,也即线性表的长度不能超过最大存储容量(数组的长度)。

          如何用代码表示一个用数组实现的线性表?首先搞清楚一个这样的线性表有哪些必要的东西。

          1. 线性表需要一个数组用来存储数据元素;
          2. 线性表需要一个最大存储容量(数组长度),即你想要“占”多少个位子,是要事先声明的,不再轻易改变;
          3. 线性表需要一个长度用来表示存了多少数据元素,线性表的长度随着数据的增删而变化,没有这个就可能导致你“塞”的数据比“占”的位子多,而“溢”出来。
          4. 1. 顺序存储结构的线性表

            总结一下,一个顺序表 (ArrayList) 由以下三部分组成:

            1. 用来实际存储数据的数组——data\[\]
            2. 用来表示线性表的最大存储容量的值——MAXSIZE
            3. 用来表示线性表的长度的值——length
            4. 1.3. 顺序表的具体实现

              有了上面的分析,下面就可以使用 C 语言的结构体来实现顺序表了。

              为了说明问题简单,我们这里的顺序表只存储整数。

              #define MAXSIZE 10 //顺序表的最大存储容量
              

              typedef struct {

              int data[MAXSIZE]; //存储数据的数组

              int length; //顺序表的长度

              } ;

              复制

              这样的一个结构体就能完美地表示一个顺序存储结构的线性表了。

              1.4. 顺序表的初始化

              孩子们已经知道公园了在哪了,但还未踏上去。

              到此为止,我们已经知道了什么是顺序存储,也知道了如何用代码表示顺序表,但仅停留在“知道”这一步,我们还未将其实际地“创造”出来放到内存中。

              要想使用一个顺序表,那么我们得先声明一个顺序表,然后将其初始化为空顺序表,也即 length = 0

              /\*\*
              

              * 初始化顺序表,将线性表的长度置为0

              * list : 要操作的顺序表的地址

              */

              void init(ArrayList *list)

              {

              list->length = 0;

              }

              复制

              注意:我们要改变顺序表的长度 length,所以要传给 init 函数的参数是一个 ArrayList 类型的指针

              ArrayList list; //声明顺序表list
              

              init(&list); //初始化list

              复制

              1.5. 顺序表的插入和删除

              现在孩子们已经来到公园了,并且已经肩并肩地排好队开始玩游戏了,现在有一名小伙伴想要加入到队伍中和他们一块玩。所以有一部分孩子为他“腾”出了位置,让他“插队”。

              1. 顺序存储结构的线性表

              由于 甲 要站在 B 的后面,所以 C、D、E 都要后退一个位置给 甲“腾空位”,然后 甲 才能“插队”到 B 后面。

              可以把孩子们站成的队伍看成线性表,把孩子看成元素,下图所示过程就是顺序表的插入元素的操作过程。

              1. 顺序存储结构的线性表

              孩子们从最后一个人开始逐个后退,后退到需要的空位为止,线性表的元素也是如此,不过线性表是使用“向后赋值”来实现“后退”的效果的。

              分析到此,代码就可以写出来了。

              /\*\*
              

              * 向顺序表的指定位置插入指定值

              * list : 顺序表的地址

              * position : 要插入的位置 (1 <= position <= list->length + 1)

              * elem : 要插入的值

              * return 0 : 插入失败;return 1 : 插入成功

              */

              int insert(ArrayList *list, int position, int elem)

              {

              if (list->length == MAXSIZE) {

              printf(“顺序表已满\n”);

              return 0;

              }

              if (position < 1 || position > list->length + 1) {

              printf(“插入位置不合法\n”);

              return 0;

              }

              for (int i = list->length - 1; i >= position - 1; i) {

              list->data[i + 1] = list->data[i]; //向后赋值

              }

              list->data[position - 1] = elem;

              list->length++;

              return 1;

              }

              复制

              注意:

              1. 需检查顺序表是否已满(length 是否等于 MAXSIZE
              2. 需检查插入位置是否合法(不能插入到表外)
              3. 插入成功后,顺序表的长度要加一
              4. 现在,刚刚插队的小孩被妈妈喊回家吃饭了,所以他需要离开队伍,这时队伍中“空出”了一个位置,所以他后面的小孩都自觉的向前一步走,使队伍更紧凑。

                1. 顺序存储结构的线性表

                孩子离队后,“空位”之后的每个孩子都逐个“向前一步走”。线性表删除元素时,使用“向前赋值”来实现孩子“向前一步走”的效果。删除操作和插入操作刚好相反,下图是其过程:

                1. 顺序存储结构的线性表

                下面是代码实现:

                /\*\*
                

                * 删除指定位置的元素,并保存其值

                * list : 顺序表的地址

                * position : 要删除的元素位置

                * elem : 保存变量的地址

                * return 0 : 删除失败;return 1 : 删除成功

                */

                int delete(ArrayList *list, int position, int *elem)

                {

                if (list->length == 0) {

                printf(“顺序表为空\n”);

                return 0;

                }

                if (position < 1 || position > list->length) {

                printf(“删除位置不合法\n”);

                return 0;

                }

                *elem = list->data[position - 1];

                for (int i = position - 1; i < list->length - 1; i++) {

                list->data[i] = list->data[i + 1];

                }

                list->length;

                return 1;

                }

                复制

                同样注意:

                1. 需检查顺序表是否为空
                2. 需检查删除位置是否合法
                3. 删除成功后,顺序表长度要减一
                4. 1.6. 顺序表的其他操作

                  至此,已经介绍了基本的“增、删、改、查”的“增和删”。

                  至于“改和查”,由于顺序表是用数组来实现的,而数组的查询和修改是及其方便的,如:

                  int a = array\[1\]; //查询
                  

                  array[2] = 5; //修改

                  复制

                  所以,顺序表的查询和修改也极为方便。

                  下面是查询的代码:

                  /\*\*
                  

                  * 查询指定位置的元素

                  * list : 要操作的顺序表

                  * position : 要查询的元素位置

                  * elem : 保存变量的地址

                  * return 0 : 查询失败;return 1 : 查询成功

                  */

                  int get(ArrayList list, int position, int *elem)

                  {

                  if (list.length == 0) {

                  printf(“顺序表为空\n”);

                  return 0;

                  }

                  if (position < 1 || position > list.length) {

                  printf(“位置不合法\n”);

                  return 0;

                  }

                  *elem = list.data[position - 1];

                  return 1;

                  }

                  复制

                  下面是更新的代码:

                  /\*\*
                  

                  * 更新指定位置的元素

                  * list : 要操作的顺序表的地址

                  * position : 要更新的元素位置

                  * elem : 要更新的值

                  * return 0 : 更新失败;return 1 : 更新成功

                  */

                  int update(ArrayList *list, int position, int elem)

                  {

                  if (list->length == 0) {

                  printf(“顺序表为空\n”);

                  return 0;

                  }

                  if (position < 1 || position > list->length) {

                  printf(“位置不合法\n”);

                  return 0;

                  }

                  list->data[position - 1] = elem;

                  return 1;

                  }

                  复制

                  以上即为针对顺序表最基础的增删改查操作,会了这四种,其他的操作也基本上可以触类旁通了。

                  1.7. 顺序表的优缺点

                  上面的那个小孩加入队伍的时候,为了给他腾位置,很多人都而向后退一步。但是才玩了一会,他就被叫回去吃饭了,之前向后退步的人又不得不再向前走一步。因为一个人,而导致很多人不得不为之变动,小孩们很不乐意。

                  写过上面四个函数,我们也会有小孩们的体会。

                  增加和删除一个元素太麻烦了,当元素很少还不明显,但当有成百上千个元素时,就需要移动大量的元素了,很麻烦,我们很不乐意。

                  查询和修改一个元素却很简单,这是数组的功劳。

                  另外,线性表的容量是固定的,大多数情况下,我们并不会提前知道线性表的容量,所以容量的分配是一个很大的问题,少了不够用,多了太浪费。像极了在快速长身体的青春期时买衣服的你。

                  总结一下:

                  优点:

                  • 查询和修改元素方便快捷
                  • 缺点:

                    • 增加和删除某个元素需要移动大量的其他元素
                    • 难以确定容量大小(所以通常会尽可能分多一点来“兜底”,但这极易造成浪费从而影响性能)

                    http://chatgpt.dhexx.cn/article/eHR2nv7X.shtml

                    相关文章

                    数据结构线性表顺序存储结构和主要算法实现

                    (1) 线性表的定义。 零个或多个数据元素的有限序列 序列线性表中有直接后继元素&#xff0c;有且仅有一个直接后继&#xff0c;有且仅有一个直接前驱&#xff0c;数据元素之间的关系是一对一的关系 常用的List操作&#xff1a; Operation InitList&#xff08;*L&#xf…

                    线性表顺序存储结构

                    1.什么是线性表? 线性表可以看作一条链子除了第一个元素和最后一个元素&#xff0c;其他每个元素都有一个前驱 元素和一个后继元素有且只有一个。 若一个元素都没有&#xff0c;则称为空表。 元素之间的关系是一一对应的关系。(就比如a2的前驱元素只有一个并且一定是a1&#…

                    线性表的顺序存储结构

                    线性表的基本概念 线性结构习惯称为线性表&#xff0c;线性表是n(n>0)个数据元素构成的有限序列&#xff0c;表中除第一个元素外的每一个元素&#xff0c;有且只有一个一个前件&#xff1b;除最后一个元素外&#xff0c;有且只有一个后件。 非空数据表具有&#xff1a; 只…

                    【数据结构】线性表的顺序存储结构及实现——C语言版

                    文章目录 顺序表1. 顺序表的存储结构定义2. 顺序表的实现2.1 初始化顺序表2.2 建立顺序表2.3 销毁顺序表2.4 判空操作2.5 求顺序表的长度2.6 遍历操作2.7 按值查找2.8 按位查找2.9 插入操作2.10 删除操作 3. 顺序表的使用4. 暖暖树洞 顺序表 线性表的顺序存储结构称为顺序表&a…

                    VUE activated,deactivated使用

                    项目中keepalive用得不多&#xff0c;记录一下以免遗忘。 页面第一次进入&#xff0c;钩子的触发顺序created-> mounted-> activated&#xff0c;退出时触发deactivated。当再次进入&#xff08;前进或者后退&#xff09;时&#xff0c;只触发activated。 事件挂载的方…

                    vue activated,deactivated生命周期的使用

                    1.当组件在 内被切换&#xff0c;它的 activated 和 deactivated 这两个生命周期钩子函数将会被对应执行。 2.activated()&#xff1a;在vue对象存活的情况下&#xff0c;进入当前存在activated()函数的页面时&#xff0c;一进入页面就触发&#xff1b;可用于初始化页面数据等…

                    vue 中 keep-alive,activated,deactivated

                    keep-alive 在组件反复切换时&#xff0c;会反复渲染&#xff0c;造成性能问题。用一个 <keep-alive></keep-alive> 标签将他包裹起来&#xff0c;组件会在第一次被创建的时候缓存下来。避免性能问题。 首先准备好组件&#xff0c;配置好路由。准备了Home,Keep,Abo…

                    【Vue】学习笔记-Vue Router activated deactivated 路由守卫

                    Vue Router activated deactivated 路由守卫 activated deactivated路由守卫1.全局守卫2.独享守卫3.组件内守卫全局路由守卫路由器的两种工作模式 activated deactivated activated 和 deactivated 是路由组件所独有的两个钩子&#xff0c;用于捕获路由组件的激活状态 具体使用…

                    vue 生命周期图 + activated + deactivated

                    一、vue 生命周期图 From the network 二、activated deactivated 除此之外&#xff0c;简单介绍一下在被keep-alive包含的组件/路由中&#xff0c;会多出两个生命周期的钩子:activated 与 deactivated。在 2.2.0 及其更高版本中&#xff0c;activated 和 deactivated 将会…

                    [Vue]缓存路由组件 activated()与deactivated()

                    前言 系列文章目录&#xff1a; [Vue]目录 老师的课件笔记&#xff0c;不含视频 https://www.aliyundrive.com/s/B8sDe5u56BU 笔记在线版&#xff1a; https://note.youdao.com/s/5vP46EPC 视频&#xff1a;尚硅谷Vue2.0Vue3.0全套教程丨vuejs从入门到精通 文章目录 前言1. 缓存…

                    Vue 钩子函数activated未触发

                    activated()和deactivated()只有在<keep-alive></keep-alive>包裹的时候才有效&#xff1b;

                    搞明白activated和deactivated

                    文章目录 写到前面什么是activatedactivated解决了一个什么问题Demomain.vueassembly1(组件1)assembly2(组件2) 执行结果要点速记个人建议写到最后 写到前面 今天简单的将activated讲一下&#xff0c;前面有人问了&#xff0c;既然有问的&#xff0c;说明还有人不是很明白的&am…

                    vue中activated

                    keep-alive <keep-alive>包裹动态组件的时候&#xff0c;会缓存不活动的组件实例&#xff0c;而不是摧毁他们。其是一个抽象的组件&#xff0c;自身不会渲染一个DOM元素&#xff0c;也不会出现在父组件链中。 说白了被<keep-alive>包裹的组件其会被缓存。 没有被…

                    Vue学习之---动态组件中的activated与deactivated钩子函数

                    Vue学习之—动态组件中的activated与deactivated钩子函数 在学习这两个钩子函数之前呢&#xff0c;怎么需要先了解下Vue内置的动态组件< component >以及与之相配套的< keep-alive > 组件&#xff1a; 动态组件指的是动态切换组件的显示与隐藏&#xff1b; < …

                    vue中keep-alive、activated的探讨和使用

                    在修改公司的一个项目的时候发现了activated这个东西&#xff0c;一直觉得很疑惑&#xff0c;之前也没怎么用过啊&#xff01;官网的生命周期那也没说过这东西啊&#xff01;生命周期不就create mount update 和destory这几个东东么&#xff0c;怎么多了个activate出来。 百思不…

                    html页面ajax提交数据,ajax请求提交form表单

                    AJAX表单提交以及数据接收 方式一 手工收集所有的用户输入&#xff0c;封装为大的“k1v1&k2v2…”键值对形式&#xff0c;使用$.post(url, data,fn)把数据提交给服务器 $.ajax({ type:post, url:Notice_noTipsNotice, data:k1v1&k2v2..., cache:false, dataType:json, …

                    接上篇 jquery.form.js 的 $.ajaxForm()和 $.ajaxSubmit()

                    2019独角兽企业重金招聘Python工程师标准>>> AjaxSubmit 和AjaxForm区别 AjaxForm ajaxForm()不能提交表单。在document的ready函数中&#xff0c;使用ajaxForm来为AJAX提交表单进行准备。提交动作必须由submit开始 , ajaxForm()适用于以表单提交方式处理ajax技术&a…

                    springboot ajax form json 请求方式

                    1.form请求的后台代码 1.定义实体 Student package com.bsx.test.entity;import com.bsx.test.constant.Gender; import com.bsx.test.constant.Nature;import javax.persistence.Column; import javax.persistence.Id; import javax.persistence.Table; import java.io.Seri…

                    ajax form表单提交 input file中的文件

                    现今的主流浏览器由于ajax提交form表单无法把文件类型数据提交到后台&#xff0c;供后台处理&#xff0c;可是开发中由于某些原因又不得不用ajax提交文件&#xff0c; 为了解决这个问题我走了不少弯路&#xff1a; 1、用原生的 input file &#xff0c; 不支持ajax上传文件&…

                    Jquery 中 ajaxSubmit 、ajaxForm使用讲解

                    最近在使用ajaxForm&#xff0c;随便把使用方法记下下来&#xff0c;以便以后回顾。 1 &#xff0c;引入依赖脚本 <script type"text/JavaScript" src"/js/jQuery/jquery.form.js"></script> //ajaxForm 依赖脚本 <script type"…