我的Github地址
小码哥《恋上数据结构与算法》笔记
极客时间《iOS开发高手课》笔记
iOS大厂面试高频算法题总结
iOS面试资料汇总
参考:小码哥数据结构与算法(四): 循环链表
数据结构和算法动态可视化
一、单向循环链表
- 尾节点的
next
,指向头节点。

二、单向循环链表接口设计
- 相较于单项链表,单向循环链表需要重写
插入节点
、删除节点
两个方法。
三、单向循环链表的实现
1、插入节点
- 插入节点,需要特别关注插入头节点的情况。此时需要拿到尾节点,然后将其
next
指向新节点。
public void add(int index, E element) {
rangeCheckForAdd(index);
if (index == 0) {
Node<E> newFirst = new Node<>(element, first);
Node<E> last = (size == 0) ? newFirst : node(size - 1);
last.next = newFirst;
first = newFirst;
} else {
Node<E> prev = node(index - 1);
prev.next = new Node<>(element, prev.next);
}
size++;
}
2、删除节点
- 如果删除的是头节点,删除后需让
last
指向新的头节点。
- 当只有一个节点并删除时,
first
指向null
。
public E remove(int index) {
rangeCheck(index);
Node<E> node = first;
if (index == 0) {
if (size == 1) {
first = null;
} else {
Node<E> last = node(size - 1);
first = first.next;
last.next = first;
}
} else {
Node<E> prev = node(index - 1);
node = prev.next;
prev.next = node.next;
}
size--;
return node.element;
}
四、双向循环链表
- 头节点的
prev
指向尾节点。
- 尾节点的
next
指向头节点。

五、双向循环链表接口设计
- 相较于双向链表,双向循环链表需要重写
插入节点
、删除节点
两个方法。
六、双向循环链表接的实现
1、插入节点
- 需特殊处理
添加第一个元素
和添加到尾节点
两种特殊情况。
public void add(int index, E element) {
rangeCheckForAdd(index);
if (index == size) {
Node<E> node = new Node<>(last, element, first);
if (size == 0) {
first = node;
last = node;
node.prev = node;
node.next = node;
}else {
last.next = node;
first.prev = node;
last = node;
}
}else {
Node<E> next = node(index);
Node<E> prev = next.prev;
Node<E> node = new Node<>(prev, element, next);
next.prev = node;
prev.next = node;
if (next == first) {
first = node;
}
}
size++;
}
2、删除节点
- 删除节点,就是在环上去掉某一个节点,然后根据删除的节点是首节点或者尾节点来处理
first
和last
。
- 需要特殊处理只有一个节点的删除操作。
public E remove(int index) {
Node<E> node = node(index);
if (size == 1) {
first = null;
last = null;
}else {
Node<E> prev = node.prev;
Node<E> next = node.next;
next.prev = prev;
prev.next = next;
if (node == first) {
first = next;
}
if (next == last) {
last = prev;
}
}
size--;
return node.element;
}