1. 链表概念及结构
概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。
链表的每一节如同火车车厢,称之节点/结点,其组成主要有两个部分:该节点所保存的数据以及下一个节点的地址(指针变量),存储地址的原因在于,链表的物理结构并不像数组一样是连续的,只有提供地址才能凭此找到下一个节点
图中指针变量plist保存的是第一个节点的地址,我们称plist此时“指向”第一个节点,如果我们希望plist“指向”第二个节点时,只需要修改plist保存的内容为0x0012FFA0。
下面是一个链表(节点)的例子
struct SListNode{
int data;
struct SListNode* next;
};
当然,为什么我们使用指针而不是直接用结构体变量?这是因为在定义结构体的时候其大小仍未确定,而结构中嵌套结构其大小就更不知道怎么算了,相较而言,不管什么类型的指针,其大小都是确定的,所以使用指针也就更加合理
另外
- 节点一般是从堆上申请的
- 每次申请的空间可能连续也可能不连续
2. 链表的分类
链表的结构非常多样,以下情况组合起来就有8种(2×2×2)
虽然有这么多的链表结构,但我们实际中最常用的还是两种结构,单链表和双向带头循环链表
- 无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如哈希桶,图的邻接表等。另外这种结构在笔试面试中出现很多
- 带头双向循环链表:结构最复杂,一般用在单独存储数据,实际中使用的链表结构,都是带头双向循环链表。结构虽然复杂,但使用这种结构会带来很多优势
3. 顺序表和链表比较
不同点 | 顺序表 | 链表 |
---|---|---|
存储空间上 | 物理上一定连续 | 逻辑连续,物理未必 |
随机访问 | 支持 | 不支持 |
任意位置插入或删除元素 | 可能需要搬移元素,效率低 | 只需修改指针指向即可 |
插入 | 动态顺序表,空间不够时需要扩容 | 没有容量的概念 |
应用场景 | 元素高效存储+频繁访问 | 任意位置插入和删除频繁 |