循环双链表之Java实现(模拟JDK中LinkedList)

单链表只有一个指针,仅仅指向当前结点的直接后继,为了弥补这个缺陷,故而引入双链表。

所谓双链表,就是每个Element都包含它本身存储的数据和两个指针,分别指向上一个和下一个Element,其结构如下:


循环双链表之Java实现(模拟JDK中LinkedList)_第1张图片

我们可以很容易的写出表示链表结点的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长于删除、添加;而短于遍历。


你可能感兴趣的:(链表,LinkedList,java 循环双向链表)