设计双向链表--LeetCode
题目
设计双向链表,则还需要属性 prev 以指示链表中的上一个节点。假设链表中的所有节点下标从 0 开始。
实现 MyLinkedList 类:
MyLinkedList()初始化MyLinkedList对象。int get(int index)获取链表中下标为index的节点的值。如果下标无效,则返回-1。void addAtHead(int val)将一个值为val的节点插入到链表中第一个元素之前。在插入完成后,新节点会成为链表的第一个节点。void addAtTail(int val)将一个值为val的节点追加到链表中作为链表的最后一个元素。void addAtIndex(int index, int val)将一个值为val的节点插入到链表中下标为index的节点之前。如果index等于链表的长度,那么该节点会被追加到链表的末尾。如果index比长度更大,该节点将 不会插入 到链表中。void deleteAtIndex(int index)如果下标有效,则删除链表中下标为index的节点。
思路
实现双向链表,即每个节点要存储本身的值,后继节点和前驱节点。除此之外,需要一个哨兵节点作为头节点 head 和一个哨兵节点作为尾节点 tail。仍需要一个 size 参数保存有效节点数。如下图所示。

初始化时,只需创建头节点 head 和 size 即可。
实现 get(index) 时,先判断有效性,然后再比较从 head 还是 tail 来遍历会比较快找到目标,然后进行遍历。如下图所示。

实现 addAtIndex(index, val) 时,如果 index 是有效值,则需要找到原来下标为 index 的节点 succ 和前驱节点 pred,并创建新节点 to_add,再通过各自 prev 和 next 变量的更新来增加to_add。最后需要更新 size。如以下两张图所示。

实现 addAtHead(val) 和 addAtTail(val) 时,可以借助 addAtIndex(index, val) 来实现。
实现 deleteAtIndex(index),先判断参数有效性。然后找到下标为 index 的节点的前驱节点 pred 和后继节点 succ,再通过各自 prev 和 next 变量的更新来删除节点,来达到删除节点的效果。同时也要更新 size。如下图所示。

class MyLinkedList {//双向链表int size;ListNode head;//虚拟头结点ListNode tail;//虚拟尾结点public MyLinkedList() {size = 0;head = new ListNode(0);tail = new ListNode(0);head.next = tail;//中间节点为空tail.prev = head;}public int get(int index) {if (index < 0 || index >= size) {return -1;}ListNode curr;//判断查询的位置在链表前半部分还是后半部分,节省循环if (index + 1 < size - index) {curr = head;//从头开始遍历for (int i = 0; i <= index; i++) {curr = curr.next;}} else {curr = tail;//从尾开始遍历for (int i = 0; i < size - index; i++) {curr = curr.prev;}}return curr.val;}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;}index = Math.max(0, index);//插入位置负数,其插入位置在链表头ListNode pred, succ;//index前一个结点、后一个结点if (index < size - index) {pred = head;for (int i = 0; i < index; i++) {pred = pred.next;}succ = pred.next;} else {succ = tail;for (int i = 0; i < size - index; i++) {succ = succ.prev;}pred = succ.prev;}size++;ListNode toAdd = new ListNode(val);toAdd.prev = pred;toAdd.next = succ;pred.next = toAdd;succ.prev = toAdd;}public void deleteAtIndex(int index) {if (index < 0 || index >= size) {return;}ListNode pred, succ;if (index < size - index) {pred = head;for (int i = 0; i < index; i++) {pred = pred.next;}succ = pred.next.next;} else {succ = tail;for (int i = 0; i < size - index - 1; i++) {succ = succ.prev;}pred = succ.prev.prev;}size--;pred.next = succ;succ.prev = pred;}
}class ListNode {int val;ListNode next;//指向下一个结点指针ListNode prev;//指向前一个结点指针public ListNode(int val) {this.val = val;}
}
