第3章-线性表的定义与实现

1,451 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第11天,点击查看活动详情

第一章《数据结构与算法是什么?》说过数据结构有四种逻辑结构,线性结构是最基本和最常用的一种,它表示的是线性结构,元素之间存在一对一的关系,数据元素之间按照某种规定存在一个顺序关系。

一、定义

假设有 nn 个同类型数据元素的有限序列,记为:

L=(a1, a2, a3, ...,ai, ..., an)L = (a_1,\ a_2,\ a_3,\ ..., a_i,\ ...,\ a_n)

它构成一个线性表,任何一种逻辑结构都可以使用顺序存储和链式存储来实现,使用顺序存储时,会在内存中分配连续的空间来存储数据元素,在程序中经常使用数组来实现。

但很多时候无法知道预先分配多大的空间合适,如果数据量较大时,内存中不存在那么大的连续空间,所以会导致内存分配失败,此时就可以使用链式存储来实现。

链式存储可以使用任何地址的空间存放数据元素,可以空间不连续,它存放的数据结点,里面包含数据元素和指向另一个数据元素的引用(或指针)。 线性表实现-存储结构.drawio.png

二、线性表基本操作

数据结构包含数据的基本操作,使用不同的存储结构来实现线性表的插入、删除、查找、遍历等基本操作。

1. 插入

初始化一组数据 (a1, a2, a3, a4, a5)(a_1,\ a_2,\ a_3,\ a_4,\ a_5) ,然后在 a2a_2 后面插入数据 a6a_6

顺序存储中,定位到 a2a_2,需要将 a3, a4, a5a_3,\ a_4,\ a_5 往后移动才能插入。 线性表实现-插入1.gif

链式存储中,定位到 a2a_2,然后把 a2a_2 的指针指向 a6a_6 ,再把 a6a_6 的指针指向 a3a_3 就完成了新节点的插入。 线性表实现-插入2.gif 由此可得链表比顺序表插入的效率高。

顺序存储需要预先分配内存空间,在插入时初始化的空间不够会抛异常。

2. 删除

初始化一组数据 (a1, a2, a3, a4, a5)(a_1,\ a_2,\ a_3,\ a_4,\ a_5) ,然后删除数据 a3a_3

顺序存储中,定位到 a3a_3 删除并释放内存,然后将 a4, a5a_4,\ a_5 往前移动。 线性表实现-删除1.gif 链式存储中,定位到 a2a_2,然后把 a2a_2 的指针指向 a4a_4 ,释放内存即可删除。 线性表实现-删除2.gif 由此可得链表比顺序表删除的效率高。

3. 查找

初始化一组数据 (a1, a2, a3, a4, a5)(a_1,\ a_2,\ a_3,\ a_4,\ a_5) ,然后查找数据 a3a_3

顺序存储中,数据在内存中是连续的,如果已知 a3a_3 的下标,可以直接获取到该数据元素。

在下标未知的情况下,也可以通过遍历来查找。 线性表实现-查找1.gif 链式存储中,数据在内存中是无序的,不能通过下标查找,只能通过遍历来查找数据。

而链式存储在遍历的时候,会增加寻址的操作。 线性表实现-查找2.gif 由此可得顺序表比链表查找的效率高。

4. 遍历

初始化一组数据 (a1, a2, a3, a4, a5)(a_1,\ a_2,\ a_3,\ a_4,\ a_5) ,然后遍历所有数据 。

顺序存储中,遍历连续内存空间上的数据元素。 线性表实现-遍历1.gif 链式存储中,通过地址引用来找到下一个数据元素,来遍历所有数据。 线性表实现-遍历2.gif 链式存储增加了寻址的操作,所以遍历的效率低于顺序存储。

三、链式存储扩展

前面讲的链式结构实现的线性表都是单向链表,可以增加结点的引用来创建更多的链表结构,比如:双向链表、单向循环链表和双向循环链表等。 线性表实现-链表种类.drawio.png

四、代码示例

具体的代码实现如下:

Gitee:gitee.com/code_artist…

GitHub:github.com/AiJiangnan/…