这里说的两种双向链表是指带“sentinel”与不带“sentinel”的,其中带"sentinel"的多了一个"sentinel"节点,以空间换取了时间。两种链表如下图:
1.不带sentinel的:
下面是构造方法以及在首项插入和删除方法,从代码中可以看出没有sentinel的DList在插入时需要处理链表为空的情况,删除的时候需要处理链表为空以及链表只有一个元素的情况,比较麻烦。
public class DList1 {
/**
* head references the first node.
* tail references the last node.
*/
protected DListNode1 head;
protected DListNode1 tail;
protected long size;
/* DList1 invariants:
* 1) head.prev == null.
* 2) tail.next == null.
* 3) For any DListNode1 x in a DList, if x.next == y and x.next != null,
* then y.prev == x.
* 4) For any DListNode1 x in a DList, if x.prev == y and x.prev != null,
* then y.next == x.
* 5) The tail can be accessed from the head by a sequence of "next"
* references.
* 6) size is the number of DListNode1s that can be accessed from the
* head by a sequence of "next" references.
*/
/**
* DList1() constructor for an empty DList1.
*/
public DList1() {
head = null;
tail = null;
size = 0;
}
/**
* DList1() constructor for a one-node DList1.
*/
public DList1(int a) {
head = new DListNode1();
tail = head;
head.item = a;
size = 1;
}
/**
* DList1() constructor for a two-node DList1.
*/
public DList1(int a, int b) {
head = new DListNode1();
head.item = a;
tail = new DListNode1();
tail.item = b;
head.next = tail;
tail.prev = head;
size = 2;
}
/**
* insertFront() inserts an item at the front of a DList1.
*/
public void insertFront(int i) {
DListNode1 insertItem = new DListNode1(i);
if(head == null){
head = insertItem;
tail = insertItem;
}else{
insertItem.next = head;
head.prev = insertItem;
head = insertItem;
}
size++;
}
/**
* removeFront() removes the first item (and node) from a DList1. If the
* list is empty, do nothing.
*/
public void removeFront() {
if(size == 0){
return;
}
if(size == 1){
head = null;
tail = null;
}else{
head.next.prev = null;
head = head.next;
}
size--;
}
下边是构造方法以及首先插入与删除方法,注意构造方法中head的prev和next在链表没有元素的情况下是指向自身的,这一点非常重要,如果设置为null,就失去了这种链表的优势,还需要像第一种链表一样在插入和删除的时候考虑多种情况。
public class DList2 {
/**
* head references the sentinel node.
*
*/
protected DListNode2 head;
protected long size;
/* DList2 invariants:
* 1) head != null.
* 2) For any DListNode2 x in a DList2, x.next != null.
* 3) For any DListNode2 x in a DList2, x.prev != null.
* 4) For any DListNode2 x in a DList2, if x.next == y, then y.prev == x.
* 5) For any DListNode2 x in a DList2, if x.prev == y, then y.next == x.
* 6) size is the number of DListNode2s, NOT COUNTING the sentinel
* (denoted by "head"), that can be accessed from the sentinel by
* a sequence of "next" references.
*/
/**
* DList2() constructor for an empty DList2.
*/
public DList2() {
head = new DListNode2();
head.item = Integer.MIN_VALUE;
head.next = head;
head.prev = head;
size = 0;
}
/**
* DList2() constructor for a one-node DList2.
*/
public DList2(int a) {
head = new DListNode2();
head.item = Integer.MIN_VALUE;
head.next = new DListNode2();
head.next.item = a;
head.prev = head.next;
head.next.prev = head;
head.prev.next = head;
size = 1;
}
/**
* DList2() constructor for a two-node DList2.
*/
public DList2(int a, int b) {
head = new DListNode2();
head.item = Integer.MIN_VALUE;
head.next = new DListNode2();
head.next.item = a;
head.prev = new DListNode2();
head.prev.item = b;
head.next.prev = head;
head.next.next = head.prev;
head.prev.next = head;
head.prev.prev = head.next;
size = 2;
}
/**
* insertFront() inserts an item at the front of a DList2.
*/
public void insertFront(int i) {
DListNode2 insertItem = new DListNode2(i);
head.next.prev = insertItem;
insertItem.next = head.next;
insertItem.prev = head;
head.next = insertItem;
size++;
}
/**
* removeFront() removes the first item (and first non-sentinel node) from
* a DList2. If the list is empty, do nothing.
*/
public void removeFront() {
if(size == 0){
return;
}
DListNode2 remove = head.next;
head.next = remove.next;
remove.next.prev = head;
size--;
}