数据结构进阶:链表原理与 Java 实现
ArrayList 的局限
在使用 Java 集合框架时,我们最常接触的是 ArrayList。通过源码分析可知,它的底层是基于数组实现的。
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
// ...
// 默认容量是 10
private static final int DEFAULT_CAPACITY = 10;
// 数组:用来存储元素
transient Object[] elementData;
// 有效元素个数
private int size;
// ...
}
由于数组在内存中是连续的空间,当我们在 ArrayList 的任意位置插入或删除元素时,必须将后续的元素整体向前或向后搬移。这一操作的时间复杂度为 O(n),效率相对较低。因此,对于需要频繁进行任意位置插入和删除的场景,ArrayList 并不是最佳选择。这时,我们就需要引入 LinkedList,即链表结构。
链表基础
概念及结构
链表是一种物理存储结构上非连续的存储结构,数据元素的逻辑顺序是通过链表中的引用链接次序实现的。
形象地理解,链表的结构类似于火车车厢的连接方式。实际开发中,链表的结构非常多样,主要可以从三个维度组合:
- 单向或者双向:节点是否只指向下一个,还是同时指向上一个。
- 带头或者不带头:是否存在一个不存数据的头结点(Dummy Head)。
- 循环或者非循环:尾节点是否指向头节点形成闭环。
虽然组合起来有八种常见形态,但在面试和实际应用中,我们重点掌握两种:
- 无头单向非循环链表:结构简单,通常不会单独用来存储数据,更多是作为其他数据结构的子结构(如哈希桶、图的邻接表)。这种结构在笔试面试中出现频率很高。
- 无头双向循环链表:Java 集合框架库中
LinkedList的底层实现就是这种结构。
链表的 Java 实现
为了深入理解链表的操作,我们可以尝试自己实现一个单链表。首先定义一个接口来规范行为。
public interface IList {
;
;
;
;
;
;
;
;
;
;
}


