双向链表
1.数据结构
public class LinkedList<E> {
private int size = 0;
private Node<E> first;
private Node<E> last;
private static class Node<E> {
E element;
Node<E> prev;
Node<E> next;
public Node(Node<E> prev, E element, Node<E> next) {
this.prev = prev;
this.element = element;
this.next = next;
}
}
}
2.获取index位置对应的节点对象
···如0 1 2 3 4这五个结点构成的双向链表size = 5
········查找2(即中间位置的元素)mid = size / 2 = 5 / 2 = 2
············从左往右即需要0和1就可以从1的next获取到2位置的元素。所以从0到mid左闭右开
············从右往左即需要4和3就可以从3的prev获取到2位置的元素。所以从size - 1 到 mid左闭右开
private Node<E> node(int index) {
rangeCheck(index);
if (index < (size >> 1)) {
Node<E> node = first;
for (int i = 0; i < index; i++) {
node = node.next;
}
return node;
} else {
Node<E> node = last;
for (int i = size - 1; i > index; i--) {
node = node.prev;
}
return node;
}
}
3.添加一个结点
(1)将结点加在中间位置,只需要获取到添加位置index处的结点更新它的prev和前一个结点的next即可,若其prev为null,则更新first等于新加入的结点node
(2)向最后加,则last指向新创建的结点,其prev为获取当前index的结点,last为null
public void add(int index, E element) {
rangeCheckForAdd(index);
// size == 0
// index == 0
if (index == size) { // 往最后面添加元素
Node<E> oldLast = last;
last = new Node<>(oldLast, element, null);
if (oldLast == null) { // 这是链表添加的第一个元素
first = last;
} else {
oldLast.next = last;
}
} else {
Node<E> next = node(index);
Node<E> prev = next.prev;
Node<E> node = new Node<>(prev, element, next);
next.prev = node;
if (prev == null) { // index == 0
first = node;
} else {
prev.next = node;
}
}
size++;
}
4.删除一个结点
(1)获取到需要删的结点的index对应的对象,将其前面结点的next更新以及其后面的结点的prev更新即可
(2)删除头结点,则first指向当前结点的next
(3)删除尾结点,则last指向当前结点的前一个接待你
public E remove(int index) {
rangeCheck(index);
Node<E> node = node(index);
Node<E> prev = node.prev;
Node<E> 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;
}