六、线性表的链式存储结构
线性表的链式存储结构称为链表(做选择题时有无尾指针是关注重点)。
在顺序表中插入和删除元素可能会导致移动大量元素的连带操作(插入或删除操作发生在表尾位置例外),而链表不会。
在单链表中找到任意一个结点的位置不像顺序表那么简单,因为顺序表支持随机存取(任意存取),而单链表不支持;
为了尽可能弥补上一条中单链表的不足,开发了双链表、循环单链表和循环双链表等存储结构,这些存储结构可以在仅知道链表中任一个结点地址的情况下推知其余所有结点的地址,但仍然不支持随机存取。
有时候还会给链表定义一个额外的指针,最常见的是表尾指针,它指向链表中最后一个结点。可以借助它来提高某些常用操作的执行效率。
线性表采用顺序存储结构,必须占用一片连续的存储单元,而采用链式存储结构则不需要这样;
从表整体来看,一般顺序表存储空间利用率低于链表;而从单个存储单元来看,顺序表存储空间利用率要高于链表。
顺序表的存储密度为百分之百,链式的存储密度小于百分之百(结点中除了数据还有指针)。
- 知识拓展——散列(Hash表)
表中的元素值通过Hash函数可以算出它在表中的元素地址。(在插入删除方面没有优势,表中元素也没有什么特定关系)
- 知识拓展——静态链表(链表的表结点指针是整型而不是指针型)
静态链表中指针指示的是链表中下一元素在数组中的地址
需要分配较大的连续空间,是一种插入删除不需要移动元素的线性表。
(一)、双链表
插入操作:把要插入元素的后继和前驱先连上 (最保险的是把参与操作的三个结点地址保存下来)
s->next=p->next;
s->prior=p;
p->next=s;
s->next->prior=s;
删除操作:把指向要删除元素的指针挪动 (和插入操作一样可通过画图辅助思考)
s->prior->next=s->next
s->next->prior=s->prior;
free(s);
(二)、循环链表
单循环列表和双循环列表在任何情况都不可能有空指针。
不带头结点的单双循环链,判空条件:Head==NULL为真。
非空的单循环链表L(带头结点)的终端结点(由p所指向)满足 p->next==L&&p!=L(因为非空)
带头结点的双循环链表L为空的条件:L->prior==L&&L->next==L