1、线性表的定义
线性表是线性结构中的一种,也是最常用、最简单的数据结构。简单来说,一个线性表就是n个同类型数据元素构成的有限序列。我们可以把线性表记为:
(a1,a2,..ai-1,ai,ai+1,....an)
ai为数据元素,其中ai-1在ai的前名,我们称ai-1是ai的直接前驱,ai+1在ai的后面,我们称ai+1是ai的直接后驱。因此,线性表也可以定义为:
- 除头尾元素外,任何一个数据元素都有且仅有一个直接前驱,有且仅有一个直接后驱;
- 有且仅有一个头元素,其有且仅有一个直接后驱;
- 有且仅有一个尾元素,其有且仅有一个直接前驱;
线性表中元素的个数为n(n>=0),被称为线性表的长度,当n为0时,则称为空表。对线性表的操作,包含访问、插入和删除等。
2、线性表的顺序存储
线性表的存储结构一般分为顺序存储和链式存储。而顺序存储主要是指用一组地址连续的存储单位依次存储线性表中的数据元素,用存储位置相邻来表示线性表中数据元素之间的逻辑关系。
假设线性表的第i个元素在存储空间中的地址为LOC(ai),则第i+1个元素的地址为LOC(ai+1)=LOC(ai)+L,(L为每一个元素占用的存储空间长度)。一般的,线性表的第i个数据元素ai的存储地址为LOC(ai)=LOC(a1)+(i-1)*L,其中LOC(a1)为线性表的第一个数据元素的位置,通常称为线性表的起始位置或基地址。
顺序存储的基本运算(或操作):
- 访问,如果需要访问第i个元素,则可以根据线性表的起始位置+(i-1)*L,算出第i个元素的存储空间位置,直接访问该元素;
- 插入,如果需要在第i个元素的后面和第i+1个元素前名,插入一个新元素,则需要将线性表的长度加1,新增一个元素的存储空间,同时将原先第i+1个元素及其之后的元素依次往后移动一个位置,将原先的第i+1的位置腾出来,放置新的元素。如下图所示;
图2.2.4 线性表的插入
- 删除,如果需要删除第i个元素,则线性表的长度减1,将第i个元素删除后,原先第i个元素的位置被腾出来,此时将原先第i+1个元素及其之后的元素依次往前移动一个位置。如下图所示;
图2.2.5 线性表的删除
3、线性表的链式存储
线性表的另一个存储结构为链式存储,区别于顺序存储,链式存储不要求每个数据元素都是相邻存储的,而是用相互独立的存储空间存储一个数据元素,同时也存储指向下一个数据元素存储空间的地址。我们把存储一个数据元素,同时也存储指向下一个数据元素地址的存储空间,称之为结点。它包含两个域,其中存储数据元素的,称为数据域,而存储指向下一个数据元素(结点)地址的,称为指针域。链式存储结构根据每个结点中的指针域数量及指针指向,又区分为线性(单)链表、双向链表和循环链表。
(1)线性单链表
线性单链表,又称线性链表,是最简单的链式存储结构,即每一个结点只包含一个指针域,且指向其直接后驱的结点地址。每一个线性链表都有一个头指针,用来指向第一个元素所在的结点位置,而线性链表的最后一个结点中,其指针域由于不需要指向任何结点,所以指针域为空,即空指针(NULL)。 如下图所示:
图2.2.6 线性链表的结点结构
图2.2.7 线性链表的结构示意图
线性链表的基本运算(或操作):
访问,如果需要访问第i个元素,则必须根据头指针,依次访问第1个至第i-1个元素,才可以得到第i个元素的位置。
插入,如果需要在第i个元素的后面和第i+1个元素前名,插入一个新元素,则需要新增一个结点,该结点的数据域存储新增的元素,其指针域指向原来的第i+1个元素的结点地址。同时原第i个结点的指针域需修改为指向新增结点的地址。
删除,如果需要删除第i个元素,则只需将第i-1的结点中的指针域修改为指向原先第i+1个结点的地址,同时将第i个结点的地址空间释放掉。
(2)循环链表
循环链表,是在单链表的基础上,增加一个头结点,头结点不存储数据元素,但其指针域指向第一个元素的结点地址,同时将最后一个结点中的指针域由空值修改为指向头结点的地址,则就形成了一个循环的链表,即可以从任何一个结点出发,都可以按照顺序循环一遍所有的结点。循环链表的示意图如下:
图2.2.8 循环链表的结构示意图
当头结点中的指针域指向其本身时,则表明该循环链表为空表,如下图所示:
图2.2.9 循环链表的空表结构示意图
(3)双向链表
双向链表,就是在单链表的基础上,在结点中新增一个指针域,用于存储其直接前驱的结点地址。这样,双向链表中的每一个结点,有一个数据域,两个指针域。如下图所示:
图2.2.10 双向链表结点示意图
在双向链表中,也有一个头指针用于指向第一个结点的地址,每个结点有两个指针域,但第一个结点中指向直接前驱的指针域为空,最后一个结点中指向直接后驱的指针域为空。双向链表示意图如下:
图2.2.11 双向链表结构示意图
由于每一个结点都设置了两个指针,所以从任何一个节点开始,都可以很快捷的找到其他任何一个结点。如果双向链表中的第一个结点的直接前驱指针指向最后一个结点的地址,而最后一个结点的直接后驱指针指向第一个结点的地址,则形成了一个双向循环链表。
【补充】顺序存储和链式存储的优缺点总结如下:
存储结构 | 优点 | 缺点 |
顺序存储 |
|
|
链式存储 |
|
|
表2.2.1