什么是链表
链表是一种重要的数据结构,是一种数据的存储方式。链表由多个链表元素组成,每个元素称为节点。链表存储的物理结构可能是连续的,但也可能是无序的。但是链表之间的元素(节点)是有序的逻辑相连。

链表是一种很灵活的数据结构,它不需要指定内存的大小,删除节点不需要要像数组那样讲数据整体向前移动,只需要更改节点的指向。但是链表的结构也决定了它的许多缺点,比如说访问需要遍历元素,不能像数组那样依靠索引,还有就是链表每个元素存的是一个对象,这是一笔非常大的内存开销。
链表从方向可以分为单向链表,双向链表。
从结构上可以分为单链表,环形链表。

Java代码实现
1 | /** |
使用链表实现栈
1 | /** |
链表和数组实现栈的比较
从复杂度来考虑,数组和链表实现的出栈入栈等操作的复杂度都相同,我们这里来测试一下。测试代码如下:
1 | // 测试使用stack运行opCount个push和pop操作所需要的时间,单位:秒 |
结果如下:

其实这个测试结果不会是稳定的,相比较之下,他们的快慢主要和环境有很大关系。
当然,ArrayStack在添加元素时可能会执行扩容操作,这个时间复杂度是O(n)的,在LinkedListStack添加元素的时候虽然没有扩容的操作但是它会执行大量new对象操作,这也是非常占用资源的。总体来说,它们的增添和删除元素的时间复杂度都是O(1),所以可以说它们执行时间的差异并不是很大。

链表实现队列
前面一篇文章专门讲到了Queue,队列就是(FIFO)的数据结构,我们主要去实现队列的入队(在队尾添加元素),出队(在队首删除元素)。回想我们前面实现的链表,在队首删除元素容易(时间复杂度是O1的),但是要在队尾添加元素就非常繁琐了,我们需要遍历整个链表,当数据量一大,我们的执行时间就会变得非常大,所以我们为了效率考虑,我们需要添加一个尾节点。
这时候我们怎么实现队列的操作呢?其实很简单,当我们入队的时候只需要将尾节点的next指向当前入队的新的节点,当然我们不得不把所有尾节点的next都置为null,为的是我们的逻辑和效率,浪费一个空间也不是大问题。
而当我们进行出队操作时,我们只需要将原来头结点变为原来头结点的next节点,返回出队节点的时候我们只需要将被删除的头结点的next节点变为null就行了
1 | /** |
三种实现对列的比较
前面我们使用了数组队列和循环队列,这时候我们加入我们刚刚实现的链表队列。测试代码如下:
1 | public class Main { |
这个时候我们能得到结果:
通过我们实践和分析,链表实现的队列也是O(1)的时间复杂度。