数据结构【线性表】图文并茂-超硬核~

简介: 亲自手绘图


开场白💨

大家好呀,今天我给大家带来数据结构中最常用和最简单的一种结构——【线性表】🚻

在介绍之前,我给大家讲个例子🏫:

在幼儿园中🏫,我们经常见到幼儿园的小朋友一个拉着一个人的衣服,依次从教室出来。而且我发现很有规律的是,每次他们的次序都是一样的。当谁走丢了的时候,可以根据谁在谁的前面,谁在谁的后面,按照事先规定好的可以在最短时间知道,并找到这个调皮的笨小孩。🧒

这种排好队的组织方式🪢,其实就是今天我要介绍的数据结构:线性表


1.线性表的定义🔴

==线性表(List):零个或多个元素的有序序列。==

线性表是具有相同数据类型的 n 个数据元素的有限序列,其中 n 为表长,当 n=0 时线性表是一个==空表==◻️。若用 L 命名线性表,则其一般表示为:L=(a1,a2,a3…ai,…an)。

  • 注意位序从 1️⃣ 开始(区分与数组下标从 0️⃣ 开始)
  • 在式中,a1 是唯一的“第一个”数据元素,又称表头元素
  • 在式中,an 是唯一的“最后一个”数据元素,又称表尾元素
  • 除第一个元素外,每个元素有且仅有一个直接前驱
  • 除最后一个元素外,每个元素有且仅有一个直接后继

先来一个大家最感兴趣的,一年里的星座列表♊,是不是线性表呢?如下图所示。当然是,星座通常都是白羊座打头♈,魔蝎收尾,当中的星座都有前驱和后继,而且一共也只有12个,所有它完全符合线性表的定义。

我们再来看🏫班级同学之间的友谊关系,是不是线性关系?哈哈😆,不是,因为每个人都可以和多个同学建立友谊,不满足线性的定义。嗯?有人就说爱情关系💕就是了。胡扯,难道每个人都有一个人爱的人和爱自己的人,而且他们还不能重复爱同一个人这样的情况出现,最终形成一个班级情感人物串联?🪢这怎么可能,也许网络小说里可能出现,但现实中是不可能的❌。


2.线性表的特点🔺

班级同学的花名册📖,是不是线性表?是,这和刚才的友谊关系是完全不同了,因为它是有限序列,也满足类型相同的特点。

在叫复杂的线性表中,一个数据元素可以由若干个数据项组成

  • 表中元素的个数有限 表中元素具有逻辑上的顺序性🎊
  • 表中元素有先后次序 表中元素都是数据元素,每个元素都是单个元素
  • 表中元素的数据类型都相同,这意味着每个元素占有相同大小的存储空间
  • 表中元素具有抽象性🙌,即讨论元素间的逻辑关系,而不考虑元素究竟表示什么内容

注意:线性表是一种逻辑结构,表示元素之间一对一的相邻关系。顺序表和链表是指存储结构,两者属于不同层面的概念,不要混淆。


3.线性表的抽象数据类型🔶

前面我们已经给出了线性表的定义,现在来分析一下,线性表应该有一些什么样的操作呢?我👩🏾‍🦰用这张图片给大家解释抽象操作:既然排队,那肯定有分先后,先来的在前面,后来的在后面,这是==添加==;后面来的人因为赶时间想排前面,这是就要==插入==;当前面的人走开了,后面一个人就往前走,而走开的人就是==输出==走了,过来的人==输入==进去;其中排队的人有我们认识的,我们需要==查找==,而人都走完了,那我们就找不到,这就是==空表==◻️。

伪代码

ADT线性表(List)

Data

   线性表的数据结构对象集合为{a1,a2,....,an},每个元素的类型均为DataType。

其中,除了第一个元素a1外,每个元素有且只有一个直接驱动元素,除了最后一个元素an外,

每一个元素有且只有一个直接后继元素。数据元素之间的关系是一对一的关系。

   InitList(&L):初始化表。构造一个空的线性表。

   Length(L): 求表长。返回线性表L的长度,即L中数据元素的个数。

   LocateElem(L,e):按值查找操作。在表L查找具有给定关键字值的元素。

   GetElem(L,i): 按位查找操作。获取表L中的第i个位置的元素的值。

   ListInsert(&L,i,e):插入操作。在表L中第i个位置插入指定元素e。

   ListDelete(&L,i,&e):删除操作。删除表L中第i个位置的元素,并用e返回删除元素的值。

   PrintList(L):输出操作。按前后顺序输出线性表L的所有元素值。

   Empty(L):判空操作。若L为空表,则返回true,否则返回false。

   DestroyList(&L):销毁操作。销毁线性表,并释放线性表L所占用的内存空间。

endADT


4.线性表的顺序存储🟡

4.1 顺序存储的定义🗨️

   说了这么多的线性表,我们来看看线性表的两种物理结构的第一种——(顺序存储结构)

==顺序表的顺序存储结构,指的是用一段地址连续的存储单元依次存储线性表的数据元素。==

4.2顺序存储方式🕐

线性表的顺序表存储的结构代码:

#define MAXSIZE 20          /* 存储空间初始分配量 */

typedefintElemType;       /* ElemType类型根据实际情况而定,这里假设为int */

typedefstruct

{

   ElemTypedata[MAXSIZE]; /* 数组,存储数据元素 */

   intlength;             /* 线性表当前长度 */

}SqList;

这里,我们发现描述顺序存储结构需要三个属性:🥩

  • 存储空间的起始位置:数组data,它的存储位置就是存储空间的存储位置。
  • 线性表的最大存储容量:数组长度MAXSIZE。Ⓜ️
  • 线性表的当前长度:length。✅

注意:① 在线性表中对元素的说法都是位序,而位序是从 1 开始的。区分与数组的下标从 0 开始。② 在顺序表中,问题的规模变量为表长 L.length。

4.3数据长度与线性长度的区别🌀

注意:这里有两个概念“数组的长度”和“线性表的长度”需要区分一下。[]    []数组的长度是存放线性表的存储空间的长度,存储分配后这个量一般是不变的。有个别同学可能会问,数组的大小一定不可以变吗?我怎么看到有书中谈到可以动态分配的一维数组。是的,一般高级语言,比如C、VB、C++都可以用编程手段实现动态分配数组,不过这会带来性能上的损耗。线性表的长度是线性表中数据元素的个数,随着线性表插入和删除操作的进行,这个量是变化的。[]    []在任意时刻,线性表的长度应该小于等于数组的长度。

4.4地址计算方法🍭

由于我们数数都是从1开始数的,线性表的定义也不能免俗,起始也是1,可C语言中的数组却是从0开始第一个下标的,于是线性表的第i个元素是要存储在数组下标为i-1的位置,即数据元素的序号和存放它的数组下标之间存在对应关系,如图:存储器中的每个存储单元都有自己的编号,这个编号称为地址


5.顺序存储结构的插入和删除〰️

5.1获得元素操作👋

对于线性表的顺序存储结构来说,如果我们要实现GetElem操作,即将线性表L中的第i个位置元素值返回,其实是非常简单的。就程序而言,只要i的数值在数组下标范围内,就是把数组第i-1下标的值返回即可。来看代码:

#define OK 1

#define ERROR 0

#define TURE 1

#define FALSE 0

typedefintStatus;

   /* Status是函数的类型,其值是函数结果状态代码,如OK等 */

   /* 初始条件:顺序线性表L已经存在,1 <= i <= ListLength(L) */

   /* 操作结果:用e返回L中第 i 个数据元素的值 */

   StatusGetElem(SqListL, inti, ElemType*e)

   {

       if (L.length==0||i<1||i>L.length)

           returnERROR;

       *e=L.data[i-1];

       returnOK;

   }

`注意这里返回值类型Status是一个整型,返回OK代表1,ERROR代表0。下文代码相同。✅

5.2插入操作🧺

刚才我们也谈到,这里的时间复杂度为O(1)。我们现在来考虑,如果我们要实现ListIn-sert(*L,i,e),即在线性表L中的第i个位置插入新元素e,应该如何操作?

来看这样一个场景:我们在春运时去买火车票,大家都排队排的好好的。这时来了一个美女,对着队伍中排在第三位的你说,“大哥,求求你帮帮忙,我家母亲有病,我得急着回去看她,这队伍这么长,你可否让我排在你的前面?”你心一软,就同意了。这时,你必须得退后一步,否则她是没法进到队伍来的。这可不得了,后面的人像蠕虫一样,全部都得退一步。骂声四起。但后面的人也不清楚这加塞是怎么回事,没什么办法。

这个例子其实已经说明了线性表的顺序存储结构,在插入数据时的实现过程如下图所示:来看下插入算法的思路:🥩

  • 如果插入位置不合理,抛出异常;
  • 如果线性表长度大于等于数组长度,则抛出异常或动态增加容量;
  • 从最后一个元素开始向前遍历到第i个位置,分别将它们都向后移动一个位置;
  • 将要插入元素填入位置i处;
  • 表长加一。✅

代码如下:

/* 初始条件:顺序线性表L已存在,1 <= i <= ListLength(L) */

/* 操作结果:在L中i个位置之前插入新的数据元素e,L的长度增加1 */

StatusListInsert(SqList*L,inti,ElemTypee)

{

   intk;

   /* 顺序线性表已经满 */

   if (L->length==MAXSIZE)

       returnERROR;

   /* 当 i 不在范围内时 */

   if (i<1||i>L->length)

       returnERROR;

   /* 若插入数据位置不在表末尾 */

   if (i<L->length)

   {

       /* 将要插入位置后数据元素向后移动一位 */

       for (k=L->length-1; k>=i-1; k--)

           L->data[k+1] =L->data[k];

   }

   /* 将新元素插入 */

   L->data[i-1] =e;

   L->length++;

   returnOK;

}

5.3删除操作❌

接着刚才的例子。此时后面排队的人群意见都很大,人们都在抱怨咋还有人插队呢,服了。就在这时,远处跑来一胖子,对着这美女喊,可找到你了,你这骗子,还我钱。只见这女子二话不说,突然就冲出了队伍,胖子追在其后,消失在人群中。哦,原来她是倒卖火车票的黄牛,刚才还装可怜。于是排队的人群,又像蠕虫一样,均向前移动了一步,骂声渐息,队伍又恢复了平静。线性表的顺序存储结构删除元素的过程,如下图:

删除算法的思路:🥩

  1. 删除算法的思路:
  2. 如果删除位置不合理,抛出异常;
  3. 取出删除元素;
  4. 从删除元素位置开始遍历到最后一个元素位置,分别将它们都向前移动一个位置;
  5. 表长减1。✅

代码如下

/* 初始条件:顺序线性表L已存在,1 ≤ i ≤ ListLength(L) */

/* 操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1 */

StatusListDelete(SqList*L,inti,ElemType*e)

{

   intk;

   /* 线性表为空 */

   if (L->length==0)

       returnERROR;

   /* 删除位置不正确 */

   if (i<1||i>L->length)

       returnERROR;

   *e=L->data[i-1];

   /* 如果删除的不是最后位置 */

   if (i<L->length)

   {

       /* 将删除位置后继元素前移 */

       for (k=i; k<L->length; k++)

           L->data[k-1] =L->data[k];

   }

   L->length--;

   returnOK;

5.4线性表顺序结构的优缺点💫


总结☑️

好了,大家休息一下🏅,等会接着写另一个存储结构。✅


目录
相关文章
|
6月前
|
存储 C语言
数据结构中的线性表链式存储介绍及其基本操作
链式存储是线性表的一种重要存储方式,它通过节点和指针的结构,实现了灵活的动态存储管理。本文介绍了单向链表的基本操作,并提供了相应的C语言代码示例。理解和掌握链表的操作对学习和应用数据结构具有重要意义。希望这篇博客能帮助你更好地理解线性表的链式存储。
139 2
|
2月前
|
存储 Java
数据结构第二篇【关于java线性表(顺序表)的基本操作】
数据结构第二篇【关于java线性表(顺序表)的基本操作】
39 6
|
2月前
|
存储
【数据结构】线性表和顺序表
【数据结构】线性表和顺序表
23 1
|
1月前
|
算法 安全 搜索推荐
2024重生之回溯数据结构与算法系列学习之王道第2.3章节之线性表精题汇总二(5)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
IKU达人之数据结构与算法系列学习×单双链表精题详解、数据结构、C++、排序算法、java 、动态规划 你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
6月前
|
算法
数据结构和算法学习记录——线性表之双向链表(上)-结点类型定义、初始化函数、创建新结点函数、尾插函数、打印函数、尾删函数
数据结构和算法学习记录——线性表之双向链表(上)-结点类型定义、初始化函数、创建新结点函数、尾插函数、打印函数、尾删函数
52 0
|
2月前
01(数据结构考研)线性表相关操作代码
01(数据结构考研)线性表相关操作代码
79 0
|
2月前
|
存储 C语言
数据结构之线性表的初始化及其操作
数据结构之线性表的初始化及其操作
46 0
|
3月前
|
存储 Java
java数据结构,线性表顺序存储(数组)的实现
文章介绍了Java中线性表顺序存储(数组)的实现。线性表是数据结构的一种,它使用数组来实现。文章详细描述了线性表的基本操作,如增加、查找、删除、修改元素,以及其他操作如遍历、清空、求长度等。同时,提供了完整的Java代码实现,包括MyList接口和MyLinearList实现类。通过main函数的测试代码,展示了如何使用这些方法操作线性表。
|
6月前
|
存储 测试技术
【数据结构】操作受限的线性表,栈的具体实现
【数据结构】操作受限的线性表,栈的具体实现
67 5
|
6月前
|
存储 测试技术
【数据结构】操作受限的线性表,队列的具体实现
【数据结构】操作受限的线性表,队列的具体实现
50 4