Gitee同步更新
- 三、linkedList(双向链表)
- 实现双向链表
- 源码分析
- 四、循环链表
- 实现单向循环列表
- 双向循环链表
JDK中linkedList就是用双向链表实现的 实现双向链表
package 链式结构.BidirectionallinkedList; public class BidirectionallinkedList{ static final int ELEMENT_NOT_FOUND = -1; private int size; private Node first; private Node last; private static class Node { E element; Node prev; Node next; public Node(Node prev, E element, Node next) { this.prev = prev; this.element = element; this.next = next; } @Override public String toString() { StringBuilder sb = new StringBuilder(); if (prev != null) { sb.append(prev.element); } else { sb.append("null"); } sb.append("_").append(element).append("_"); if (next != null) { sb.append(next.element); } else { sb.append("null"); } return sb.toString(); } } public void clear() { size = 0; first = null; last = null; } public E get(int index) { return node(index).element; } public E set(int index, E element) { Node node = node(index); E old = node.element; node.element = element; return old; } public void add(int index, E element) { rangeCheckForAdd(index); // size == 0 // index == 0 if (index == size) { // 往最后面添加元素 Node oldLast = last; last = new Node<>(oldLast, element, null); if (oldLast == null) { // 这是链表添加的第一个元素 first = last; } else { oldLast.next = last; } } else { Node next = node(index); Node prev = next.prev; Node node = new Node<>(prev, element, next); next.prev = node; if (prev == null) { // index == 0 first = node; } else { prev.next = node; } } size++; } public E remove(int index) { rangeCheck(index); Node node = node(index); Node prev = node.prev; Node next = node.next; if (prev == null) { // index == 0 first = next; } else { prev.next = next; } if (next == null) { // index == size - 1 last = prev; } else { next.prev = prev; } size--; return node.element; } public int indexOf(E element) { if (element == null) { Node node = first; for (int i = 0; i < size; i++) { if (node.element == null) {return i;} node = node.next; } } else { Node node = first; for (int i = 0; i < size; i++) { if (element.equals(node.element)) {return i;} node = node.next; } } return ELEMENT_NOT_FOUND; } private Node node(int index) { rangeCheck(index); if (index < (size >> 1)) { Node node = first; for (int i = 0; i < index; i++) { node = node.next; } return node; } else { Node node = last; for (int i = size - 1; i > index; i--) { node = node.prev; } return node; } } @Override public String toString() { StringBuilder string = new StringBuilder(); string.append("size=").append(size).append(", ["); Node node = first; for (int i = 0; i < size; i++) { if (i != 0) { string.append(", "); } string.append(node); node = node.next; } string.append("]"); return string.toString(); } private void outOfBounds(int index){ throw new IndexOutOfBoundsException("Index"+index+",Size:"+size); } private void rangeCheck(int index){ if (index < 0 || index >= size){ outOfBounds(index); } } private void rangeCheckForAdd(int index){ if (index < 0 || index > size){ outOfBounds(index); } } }
总结:双向链表对于单向链表操作数量缩减了一半。
对比动态数组:
- 动态数组:开辟、销毁内存空间的次数相对较少,但可能造成内存空间的浪费。(可以通过缩容解决)
- 双向链表:开辟、销毁内存空间的操作次数相对较多,但不会造成内存空间的浪费。
与单向链表的不同: 添加、删除操作需要维护最后一个节点。
if(index == 0){
first = new Node<>(element,first);
//最后一个节点
Node last = (size == 0) ? first : node(size -1);
last.next = first;
}
双向循环链表



