为什么引入双链表?单链表的结点中只有一个指向其后继的指针,使得单链表要访问某个结点的前驱结点时,只能从头开始遍历,访问后驱结点的复杂度为O(1),访问前驱结点的复杂度为O(n)。为了克服上述缺点,引入了双链表。 单向链表查找的方向只能是一个方向,而双向链表可以向前或者向后查找;单链表如果想要实现删除操作,需要找到待删除节点的前一个节点。而双向链表可以实现自我删除。 ![[104421_43592.png]] ![[104543_51020.png]] 双链表的遍历与单链表相同,可以从头或者从尾反向遍历,参考java LinkedList源码可以实现先判断下标处于的位置来选择从头或者尾遍历提高性能 以下是双链表部分实现 ```java public class DoubleLinkList { /** * 头节点 */ private Node first; /** * 尾节点 */ private Node tail; /** * 元素数量 */ private int size; public DoubleLinkList() { } /** * 头插法 * * @param data */ public void addFirst(T data) { Node newNode = new Node<>(data); if (size == 0) { //只有一个元素时,头、尾都是同一个 first = newNode; tail = newNode; } else { newNode.next = first; first.prev = newNode; first = newNode; } size++; } /** * 尾插法 * * @param data */ public void addLast(T data) { if (size == 0) { addFirst(data); } else { Node newNode = new Node<>(data); newNode.prev = tail; tail.next = newNode; tail = newNode; size++; } } /** * 插入指定位置 * * @param data * @param index */ public void insert(T data, int index) { checkIndex(index); if (index == 0) { addFirst(data); } else if (index == size) { addLast(data); } else { Node newNode = new Node<>(data); //从头遍历,可以判断index实现从头或尾遍历 Node head = first; for (int i = 0; i < index - 1; i++) { head = head.next; } newNode.next = head.next; head.next = newNode; newNode.prev = head; newNode.next.prev = newNode; size++; } } /** * 根据下标获取元素 * * @param index * @return */ public T getByIndex(int index) { checkIndex(index); Node node = first; for (int i = 0; i < index; i++) { node = node.next; } return node.element; } /** * 打印输出 */ public void display() { Node node = first; System.out.println(node.element); for (int i = 0; i < size - 1; i++) { node = node.next; System.out.println(node.element); } } /** * 计算元素数量 * * @return */ public int sizeOf() { return size; } /** * 校验下标 * * @param index */ private void checkIndex(int index) { if (index < 0 || index > size) { throw new IndexOutOfBoundsException(); } } /** * 链表节点对象 * * @param */ private static class Node { /** * 元素 */ T element; /** * 后指针 */ Node next; /** * 前指针 */ Node prev; public Node(T element) { this.element = element; } } } ```