一. 双向链表的特点
- 每个节点维护了prev,next 两个节点和 元素e
- 不仅可以像单链表向后查找,还可以向前查找。
- 添加/删除第一个节点和最后一个节点一个节点的时间复杂度都是O(1)
- 查找的时候,可以判断index 在前半部分还是后半部分,查找节点。
二.双向链表的插入和删除
插入节点:首先找到要插入节点newNode的位置,并且找到前一个节点prevNode,和后一个节点nextNode, prevNode的next 指向新的节点,newNode的prev 指prevNode,newNode节点next指向nextNode,nextNode的prev指向newNode 示意图如下:
删除节点:找到删除delNode的节点的位置,并且找到前一个节点prevNode,和后一个节点nextNode, prevNode的next 指向nextNode,newNode的prev 指prevNode ,如下图:
三. 双向链表时间复杂度分析
- 删除/新增 第一个和最后一个元素的时间复杂度为O(1)
- 删除/新增 元素的时间复杂度为O(n)
四.Java 双向链表的简单实现
/**
* @author 一直往前走
* @date 2019/08/02
*/
public class DoubleList<E> {
public Node<E> first;
public Node<E> last;
public int size;
public int modCount;
public DoubleList() {
}
/**
* 添加第一个元素
*
* @param e
*/
public void addFirst(E e) {
final Node f = first;
final Node newNode = new Node<E>(null, e, f);
if (f == null) {
last = newNode;//newNode赋值last
} else {
first.prev = newNode; //newNode赋值给first.prev
}
newNode.next = first;
first = newNode;
size++;
modCount++;
}
/**
* 添加最后一个元素
*
* @param e
*/
public void addLast(E e) {
final Node l = last;
final Node newNode = new Node(l, e, null);
if (l == null) {
first = newNode;
} else {
last.next = newNode;
}
newNode.prev = last;
last = newNode;
size++;
modCount++;
}
public void add(int index, E e) {
if (index < 0 || index > size) {
throw new IllegalArgumentException("Add failed. index illegal");
}
if (index == 0) {
addFirst(e);
} else if (index == size) {
addLast(e);
} else {
addBefore(e, node(index));
}
}
/**
* 根据index位置获取节点
* 利用双向链表的特点提高查找效率
*
* @param index
* @return
*/
private Node<E> node(int index) {
if (index < (size >> 1)) { //说明要查找的节点在前半部分
Node<E> x = first;
for (int i = 0; i < index; i++) {
x = x.next;
}
return x;
} else { //说明要查找的节点在前半部分
Node<E> x = last;
for (int i = size - 1; i > index; i--) {
x = x.prev;
}
return x;
}
}
/**
* 在节点node前添加元素e
*
* @param e
* @param node
*/
public void addBefore(E e, Node node) {
Node prev = node.prev;
Node newNode = new Node(prev, e, node);
if (prev == null) {
first = newNode;
} else {
prev.next = newNode;
}
node.prev = newNode;
size++;
modCount++;
}
/**
* 在节点node后添加元素e
*
* @param e
* @param node
*/
public void addAfter(E e, Node node) {
Node next = node.next;
Node newNode = new Node(node, e, next);
if (next == null) {
last = newNode;
} else {
next.prev = newNode;
}
node.next = newNode;
size++;
modCount++;
}
/**
* 双链表
*
* @param <E>
*/
class Node<E> {
public E e;
public Node next, prev;
public Node() {
e = null;
next = null;
prev = null;
}
public Node(Node prev, E e, Node next) {
this.e = e;
this.prev = prev;
this.next = next;
}
public String toString() {
StringBuilder sb = new StringBuilder();
Node cur = this;
while (cur != null) {
sb.append(cur.e + "->");
cur = cur.next;
}
sb.append("NULL");
return sb.toString();
}
}
public static void main(String[] args) {
DoubleList<Integer> doubleList = new DoubleList();
for (int i = 0; i < 10; i++) {
doubleList.addFirst(i);
System.out.println(doubleList);
}
doubleList.add(1, 2);
System.out.println(doubleList);
}
}