单链表只有一个指针,仅仅指向当前结点的直接后继,为了弥补这个缺陷,故而引入双链表。
所谓双链表,就是每个Element都包含它本身存储的数据和两个指针,分别指向上一个和下一个Element,其结构如下:
我们可以很容易的写出表示链表结点的Java Code:
private T value=null;//use storage data private Node<T> previous=null;//a reference which means the previous object of current node private Node<T> next=null;//a reference which means the next object of current node /** * the constructor of Node * @param value * @param previous * @param next */ public Node(T value, Node<T> previous, Node<T> next) { this.value = value; this.previous = previous; this.next = next; }
而循环双链表的所有操作,几乎都是围绕头结点操作的。下面是add方法:
private void addBefore(Node<T> currentNode,T value){ /* * constructor a object of Node<T>,the value of this object is the param of object * the previous of this value is headNode.previous(value=[null],previous=headNode,next=headNode) * the next of this object is headNode(value=[null],previous=headNode,next=headNode) */ Node<T> newNode=new Node<T>(value, currentNode.previous, currentNode); newNode.previous.next=newNode; newNode.next.previous=newNode; size++; }
remove方法如下:
public T remove(int index){ rangeCheck(index); Node<T> node=getNode(index); T result = node.value; node.previous.next = node.next; node.next.previous = node.previous; size--; return result; }
package com.lemon.linkedlist; /** * This class realize the linkedlist of data structures * The object of MyLinkedList is good at the operation such as add or remove, * and the disadvantage is random access. * @author yanan * @param <T> */ public class MyLinkedList<T> { /** * the number of this list */ private int size; /** * construction method */ public MyLinkedList (){ headNode.next = headNode.previous = headNode; } /** * the header of this list */ private Node<T> headNode=new Node<T>(null, null, null); /** * return a number of objects in this list * @return */ public int size(){ return size; } /** * test this list whether is null or not * @return */ public boolean isEmpty(){ return size==0; } /** * add an object to list * @param object * @return */ public boolean add(T object){ addBefore(headNode,object); return true; } /** * get an object at specified position in this list * @param index * @return */ public T get(int index){ rangeCheck(index); return this.getNode(index).value; } private void rangeCheck(int index){ if (index < 0 || index >= size) throw new IndexOutOfBoundsException("Index: "+index+ ", Size: "+size); } /** * return an array which contains all object,which belong to the list,from head to the last. * @return */ public Object[] toArray(){ Object[] result=new Object[size()]; for(int i=0;i<result.length;i++){ result[i]=headNode.next.value; headNode=headNode.next; } return result; } private Node<T> getNode(int index){ Node<T> e = headNode; for(int i=0;i<size();i++){ if(i==index){ return e.next; }else{ e=e.next; } } return e; } /** * remove an object at specified position which on behalf of index in this list * return an object that has been removed from this list. * @param index * @return */ public T remove(int index){ rangeCheck(index); Node<T> node=getNode(index); T result = node.value; node.previous.next = node.next; node.next.previous = node.previous; size--; return result; } private void addBefore(Node<T> currentNode,T value){ /* * constructor a object of Node<T>,the value of this object is the param of object * the previous of this value is headNode.previous(value=[null],previous=headNode,next=headNode) * the next of this object is headNode(value=[null],previous=headNode,next=headNode) */ Node<T> newNode=new Node<T>(value, currentNode.previous, currentNode); newNode.previous.next=newNode; newNode.next.previous=newNode; size++; } /** * a static class,which object that on behalf of an object of the MyLinkedList class * @author yanan * @param <T> */ private static class Node<T> { private T value=null;//use storage data private Node<T> previous=null;//a reference which means the previous object of current node private Node<T> next=null;//a reference which means the next object of current node /** * the constructor of Node * @param value * @param previous * @param next */ public Node(T value, Node<T> previous, Node<T> next) { this.value = value; this.previous = previous; this.next = next; } } }
测试如下:
package com.lemon.linkedlist; public class TestMyLinkedList { /** * @param args */ public static void main(String[] args) { MyLinkedList<String> list=new MyLinkedList<String>(); /** * test add and get */ list.add("ChangNinNa"); list.add("ChangNinMeng"); list.add("ChangNinFang"); System.out.println("after add...."); for(int i=0;i<list.size();i++){ System.out.println(list.get(i)); } /** * test remove */ list.remove(0); System.out.println("after remove...."); for(int i=0;i<list.size();i++){ System.out.println(list.get(i)); } /** * test toArray */ Object[] objs=list.toArray(); for(int i=0;i<objs.length;i++){ System.out.println(objs[i]); } } }
当明白了双向链表的原理后,可以很容易理解:为什么Java中LinkedList长于删除、添加;而短于遍历。