与单向链表不同之处:
不光定义了后继节点next,还定义了前驱节点pre。设置了虚拟头节点head和虚拟尾节点tail。这样做不光可以从前向后遍历,还可以从后往前遍历,方便更快的查找结点。
在addAtIndex,deleteAtIndex方法中,都需要快速找到当前的节点,所以将查找当前节点的方法抽取出来,定义一个getNode()方法,用最快的查找方式查找。
public class MyLinkedList {
static class ListNode {
int val;
ListNode next;
ListNode pre;
public ListNode(int val) {
this.val = val;
}
}
int size;
ListNode head, tail;
//构造方法,初始化链表,定义长度,头节点,尾节点
public E02MyLinkedList2() {
size = 0;
head = new ListNode(0);
tail = new ListNode(0);
head.next = tail;
tail.pre = head;
}
public int get(int index) {
if (index < 0 || index >= size) {
return -1;
}
return getNode(index).val;
}
public ListNode getNode(int index) {
ListNode curr;
//判断更短路径
if (index >= size / 2) {
//tail开始
curr = tail;
for (int i = 0; i < size - index; i++) {
curr = curr.pre;
}
} else {
curr = head;
for (int i = 0; i <= index; i++) {
curr = curr.next;
}
}
return curr;
}
public void addAtHead(int val) {
addAtIndex(0, val);
}
public void addAtTail(int val) {
addAtIndex(size, val);
}
public void addAtIndex(int index, int val) {
if (index > size) {
return;
}
ListNode addNode = new ListNode(val);
ListNode pred = head;
if (index <= 0) {
index = 0;
}
if (index == size) {
//获得最后一个节点
pred = getNode(index - 1);
} else {
pred = getNode(index).pre;
}
addNode.next = pred.next;
pred.next.pre = addNode;
addNode.pre = pred;
pred.next = addNode;
size++;
}
public void deleteAtIndex(int index) {
if (index < 0 || index >= size) {
return;
}
if (index == 0) {
}
//找到index的前驱
ListNode curr = getNode(index);
curr.next.pre = curr.pre;
curr.pre.next = curr.next;
size--;
}
}