链表通常指的是单向链表,他包含多个节点,每个节点都有一个纸箱下一个几点的next指针。表中最后一个节点指向NULL,表示链表的结束。
下面是一个基于Java 声明的链表节点
public class Node<T extends Serializable> {// 节点数据private T data;// 指向的Next 节点private Node<T> next;}
- 遍历链表
- 在链表中插入一个元素
- 在链表中删除一个元素
1.1 链表的遍历
假设表头节点是指向链表的第一个节点,完成链表的遍历只需要执行以下步骤。很简单可以在链表中查找的时间复杂度为
- 沿指针遍历
- 显示当前指针所指向的内容
- 将当前节点指向 Next 节点
- 当 Next 节点指向NULL的时候遍历结束
public static <T extends Serializable> void linkedListForeach(Node<T> headNode) {Node<T> currentNode = headNode;// 4. 遍历终止条件,Next指向NULLwhile (currentNode != null) {// 2.输出当前节点的数据System.out.println(currentNode.getData() + "->");// 3. 将当前节点指向Next 节点currentNode = currentNode.getNext();}}
根据同样的逻辑,也可以根据此实现链表长度的计算。
private static <T extends Serializable> int length(Node<T> headNode) {Node<T> currentNode = headNode;int count = 0;while (currentNode != null) {count++;currentNode = currentNode.getNext();}return count;}
1.2 链表插入元素
链表中插入元素分为三种,分别是在链表头部插入元素,在链表中间插入元素以及在链表尾部插入元素。需要注意的这里的链表的位置指的在p位置插入元素,在插入完成之后,链表的p位置指向的是新的节点。 针对插入操作其时间复杂度同查找一致,在头部插入元素的时间复杂度为 ,在中间以及尾部节点插入的时间复杂度为
主要的体现在对节点位置的查找上。
1.2.1 在链表的头部插入新的节点

其逻辑步骤是:
- 首先将新的节点的指针指向表头节点
- 将表头节点指向新的节点
1.2.2 在链表尾部插入节点

在链表尾部插入新的节点也非常简单,需要将新的节点的NEXT 指针指向NULL,然后将原链表的尾指针执行新节点,即可。
1.2.3 在链表中间插入节点

- 首先定位到需要插入的节点位置,断开其 Next 节点,注意需要保存 Next 节点的引用
- 将当前节点的 Next 指针执行新的节点
- 将新节点的 Next 指针指向 Next 节点
1.2.4 源码示例
// 时间复杂度 O(n) 空间复杂度 O(1)private static <T extends Serializable> Node<T> insert(Node<T> headNode, Node<T> insertNode, int position) {// 判断长度,插入的位置是否合法int length = length(headNode);if (position <= 0 || position > length) {throw new IllegalArgumentException();}// 如果是链表头部,直接指向Next节点if (position == 1) {insertNode.setNext(headNode);return insertNode;}// 如果不是头部,那么获取到当前插入位置的节点Node<T> currentNode = findByPosition(headNode, position - 1);if (currentNode == null) {return headNode;}// 保存当前插入位置节点的Next引用Node<T> next = currentNode.getNext();// 当前节点的Next 指向新的节点currentNode.setNext(insertNode);// 新的节点的Next 指向Next节点insertNode.setNext(next);return headNode;}
1.3 链表删除元素
同插入类似,链表删除也分为三种情况,分别是在删除链表头部元素,删除链表中间元素以及在删除链表尾部元素。 针对删除操作其时间复杂度同查找一致,删除头部元素的时间复杂度为 ,删除中间以及尾部节点的时间复杂度为
主要的体现在对节点的查找
1.3.1 删除链表头部节点

删除头部节点元素非常简单,只需要将原头部节点的NEXT指向NULL,然后将表头指针指向原头结点的Next节点即可。
1.3.2 删除链表尾部节点

删除尾部节点也非常简单,只要将尾部节点的前驱的Next节点设置为NULL,即可
1.3.3 删除链表中间的节点

删除链表的中间节点的步骤是:
- 定位当前节点为需要删除节点的前驱位置,当前节点的后驱就是即将删除的节点
- 将删除节点的Next 指向NULL
- 将当前节点的Next指针执行将要删除的节点的Next节点。
1.3.4 代码示例
// 时间复杂度 O(n) 空间复杂度 O(1)private static <T extends Serializable> Node<T> remove(Node<T> headNode, int position) {int length = length(headNode);if (position <= 0 || position > length) {throw new IllegalArgumentException();}// 如果是删除头部节点,直接返回头部节点的Nextif (position == 1) {headNode.setNext(null);return headNode.getNext();}// 定位到删除节点的前驱节点,以及即将删除的节点Node<T> preNode = findByPosition(headNode, position - 1);Node<T> currentNode = findByPosition(headNode, position);// 如果前驱节点存在,则将前驱节点的Next设置为删除节点的Nextif (preNode != null) {Node<T> next = Objects.isNull(currentNode) ? null : currentNode.getNext();preNode.setNext(next);}return headNode;}
