线性表的链式存储结构
1、线性表链式存储结构定义
先看个图
线性表的链式存储结构的特点是用一组任意的存储单元存储线性表的数据元素,这组存储单元可以是连续的,也可以是不连续的。这就意味着,这些数据元素可以存在内存未被占用的任意位置。
以前的顺序存储结构中,每个数据元素只需要存储数据元素就可以了。现在链式结构中,处理要存储数据元素信息之外,还要存储它的后继元素的存储地址。
为了表示每个元素ai与其直接后继元素ai+1之间的逻辑关系,对数据元素ai来说,除了存储其本身的信息之外,还需要存储一个指示其直接后继的信息(即直接后继的存储位置)。把存储数据元素的域称为数据域,把存储直接后继位置的域称为指针域。指针域中存储的信息称作指针或链。这两部分信息组成数据元素ai的存储映像,称为结点。
n个结点链结成一个链表,即为线性表(a1,a2,a3…an)的;链式存储结构,因为此链表的每个结点中只包含一个指针域,所以叫做单链表。
链表的第一个结点存储位置叫做头指针,最后一个结点指针指向NULL。如图:
一般地,我们为了方便,会在单链表的第一个结点前附设一个结点,称为头节点。头节点的数据域可以不存任何数据,也可以存一些线性表的长度等信息。
综上,结点由存放数据元素的数据域和存放后继结点的地址的指针域组成。
2、头指针和头节点的异同
头指针:
- 头指针是指链表指向第一个结点的指针,若链表由头节点,则是指向第一个元素结点的指针;
- 头指针具有标识作用,所以常用头指针冠以链表的名字;
- 无论链表是否为空,头指针均不为空。头指针是链表的必要元素。
头结点:
- 头节点是为了操作的统一和方便而设立的,放在第一个元素结点之前,其数据域一般无意义;
- 有了头节点,对在第一个元素结点前插入结点和删除第一个元素结点,其操作与其他结点的操作就统一了;
- 头节点不一定是链表的必要元素。
单链表的读取
算法思路:
- 声明一个指针p指向链表第一个结点,初始化j从1开始;
- 当j<i时,就遍历链表,让p的指针向后移动,不断指向下一个结点,j累加1;
- 若到链表末尾p为空,则说明第i个结点不存在;
- 否则查找成功,返回结点p的数据。
其核心思想就是工作指针后移。其时间复杂度为O(n)。
单链表的插入和删除
单链表的插入
看图说话
算法思路:
- 声明一指针p指向链表头节点,初始化j从1开始;
- 当j < i 时,就遍历链表,让p的指针向后移动,不断指向下一个结点,j累加1;
- 若到链表末尾p为空,则说明第i个结点不存在;
- 否则查找成功,在系统中生成一个空结点s;
- 将数据元素e赋值给 s->data;
- 单链表的插入标准语句 s->next; p->next=s;
- 返回成功。
单链表的删除
上图
算法思路:
- 声明一指针p指向链表的头指针,初始化j从1开始;
- 当j< i时,就遍历链表,让p的指针向后移动,不断指向下一个结点,j累加1;
- 若到链表末尾p为空,则说明第i个结点不存在;
- 否则查找成功,将欲删除的结点p->next赋值给q;
- 单链表的删除标准语句 p->next=q->next;
- 将q结点中的数据赋值给e,作为返回;
- 释放q结点;
- 返回成功。
从整个算法来说,单链表的删除和插入的时间复杂度都是O(n)。
显然,对于插入或删除数据越频繁的操作,单链表的效率优势就越明显。
单链表的整表创建
顺序存储结构的创建,其实就是一个数组的初始化,即声明一个类型和大小的数组并赋值的过程。
对于单链表来说,它所占用的空间的大小和位置是不需要预先分配划定的,可以根据系统情况即时生效。
算法思路:
- 声明一指针p和计数器变量i;
- 初始化一空链表L;
- 让L的头节点的指针指向NULL,即建立一个带头节点的单链表;
- 循环:
生成一新结点赋值给p;
随机生成一个数字赋值给p的数据域p->data;
将p插入到头节点与前一新结点之间。
以上思路称作头插法,当然对应还有尾插法,不再累赘。
单链表的整表删除
算法思路:
- 声明一结点p和q;
- 将第一个结点赋值给p;
- 循环:
将下一节点赋值给q;
释放p;
将q赋值给p。
两种结构优缺点
存储分配方式
- 顺序存储结构用一段来内需的存储单元依次存储线性表的数据元素;
- 单链表采用链式存储结构,用一组任意的存储单元存放线性表的元素;
时间性能
a、查找
顺序存储结构O(1)
单链表O(n)
b、插入和删除
顺序存储结构需要平均移动表长一般的元素,时间为O(n)
单链表在选出某位置的指针后,插入和删除的时间仅为O(1)
空间性能
- 顺序存储结构需要预分配存储空间,分大了,浪费,分小了易发生上溢;
- 单链表不需要分配存储空间,只要有就可以分配,元素个数也不受限制。
总结来说:
- 顺序结构查找快,增删慢;
- 链表 查找慢,增删快;
- 元素个数不大或根本不变或事先知道其最大容量时,可以采用顺序存储结构;
- 当元素变化大或根本不知道多大,应采用链表,不考虑内存空间大小的问题。