链表是这样的一种数据结构,其中的各个对象按照线性顺序排列。链表又有单向链表、双向链表、有序链表、无序链表、循环链表及以上各特性组合的链表等,链表尾动态集合提供了一种简单而灵活的表示方法。
与数组的线性顺序由其下标决定不同的是,链表的顺序由各个对象里的指针决定。一般情况下,链表由节点(node)串联而成,而每个节点里都有指向下一节点(next)或上一节点(previous)的指针(或引用)。对于特殊的两个节点,表头节点的上个节点和表尾节点均由null表示。除节点外,一个链表还应有一个表头指针(L.head)指向表头(head),表征遍历开始的地方。当表头指针指向null时,表征此链表为空。
本文Java实现了一个简单的双向链表,Node类是组成链表的节点,其中有key、prev、next属性,还有其相应的set、get方法。MyLinkedList类是双向链表的实现类,其中包含一个指向表头节点的引用。注意,本次实现的insert操作只是简单的将节点插到队尾。
由于表头和表尾的特殊性给链表的操作带来了许多不方便,为简化边界处的处理,可以在链表中设置一个哨兵节点,这个节点是一个空节点。原设计中所有指向null的节点均可以指向这个哨兵节点(L.Null节点),此时L.Null节点的prev指向尾节点,L.Null节点的next指向头节点。这样的调整将一个常规的双向链表转变为一个有哨兵的双向循环链表,哨兵位于头尾之间,消除了边界条件。由于L.Null的next节点表征头节点,L.head也没有必要存在了。但是,这样做的代价是付出了一个空节点的存储空间,对短链表并不推荐,本文也并未实现。
class Node<T> {
private Node<T> next;
private Node<T> prev;
private T key;
public Node(T key, Node<T> prev, Node<T> next) {
this.key = key;
this.prev = prev;
this.next = next;
}
public Node<T> getNext() {
return this.next;
}
public void setNext(Node<T> next) {
this.next = next;
}
public void setprevious(Node<T> prev) {
this.prev = prev;
}
public void setKey(T key) {
this.key = key;
}
public Node<T> getprevious() {
return this.prev;
}
public T getKey() {
return this.key;
}
public String toString() {
return key.toString();
}
}
public class MyLinkedList<T> {
Node<T> head;
public MyLinkedList() {
head = null;
}
public void insert(T key) {
if (head == null)
head = new Node<T>(key, null, null);
else{
Node<T> x = head;
while(x.getNext() != null){
x = x.getNext();
}
x.setNext(new Node<T>(key, x, null));
}
}
public Node<T> search(T key) {
Node<T> x = head;
while (x != null && !(x.getKey().equals(key)))
x = x.getNext();
return x;
}
public void delete(T key) {
Node<T> x = head;
while (x != null && !(x.getKey().equals(key)))
x = x.getNext();
if (x != null) {
if (head.equals(x)) {
x.getNext().setprevious(null);
head = x.getNext();
} else {
x.getNext().setprevious(x.getprevious());
x.getprevious().setNext(x.getNext());
}
}
}
public void set(T old, T key) {
Node<T> x = head;
while (x != null && !(x.getKey().equals(old))){
x = x.getNext();
}
if (x != null)
x.setKey(key);
}
}