Java手寫LinkedList 應用數據結構之雙向鏈表

作爲Java程序員,紮實的數據結構算法能力是必須的

LinkedList理解的最好方式是,自己手動實現它

        ArrayList和LinkedList是順序存儲結構和鏈式存儲結構的表在java語言中的實現.

  ArrayList提供了一種可增長數組的實現,使用ArrayList,因爲內部使用數組實現,所以,它的優點是,對於get和set操作調用花費常數時間.缺點是插入元素和刪除元素會付出昂貴的代價.因爲這個操作會導致後面的元素都要發生變動,除非操作發生在集合的末端.

  鑑於這個缺點,如果需要對錶結構的前端頻繁進行插入,刪除操作,那麼數組就不是一個好的實現,爲此就需要使用另一種結構,鏈表,而LinkedList就是基於一種雙鏈表的實現,使用它的優點就是,對於元素的插入,刪除操作開銷比較小,無論是在表的前端還是後端.但是缺點也顯而易見,對於get操作,它需要從表的一端一個一個的進行查找,因此對get的調用花費的代價也是很昂貴的.

  理解這集合最好的方式就是自己去實現它,下面我們通過代碼來實現自己的LinkedList.

注意點:在學習數據結構的雙向鏈表,會學習頭結點和尾結點,加上頭結點和尾結點,操作其他結點可以保持同一個動作,但是在JDK實現雙向鏈表代碼中,沒有加頭結點和尾結點,下面看LinkedList實現的簡易版

public class LinkedList<E> implements Iterable<E> {
	
	private int size;
	
	private Node first;
	private Node last;
	
	//靜態內部類
	private static class Node<E>{
		private E data;
		private Node prev;
		private Node next;
		
		public Node(E data, Node prev, Node next) {
			super();
			this.data = data;
			this.prev = prev;
			this.next = next;
		}
	}
	
	//不添加頭結點和尾結點
	public void add(int index,E e){
		testIndex(index);
		
		//根據index位置,選擇不同的方式添加結點
		if(index == size){
			lastNode(e);
		}else
			//使用node()方法,查找到當前index位置的node結點
			beforeNode(node(index),e);
	}
	
	//根據索引,插入結點,參數node爲插入前,需要插入位置的node
	private void beforeNode(Node<E> node, E e) {
		final Node<E> pnode = node.prev;
		final Node<E> nnode = node;
		final Node<E> newNode  = new Node<E>(e, pnode,nnode );
		//爲插入的兩邊結點分別添加前後指針域
		pnode.next = newNode;
		nnode.prev = newNode;
		
		size++;
	}

	//默認直接在鏈表尾部添加結點
	public void add(E e){
		this.add(size,e);
	}
	
	//根據索引值,在鏈表中查找到當前位置結點
	private Node<E> node(int index) {
		if(index<size>>1){
			Node<E> node = first;
			for(int i = 0;i<index;i++)
			{
				node  = node.next;
			}
			return node;
		}else{
			Node<E> node = last;
			for(int i= size-1;i>index;i--){
				node = node.prev;
			}
			return node;
		}
	}

	//在jdk源碼中,只有根據索引值來取值
	public E get(int index){
		Node<E> node = (Node) node(index);
		return node.data;
	}
	
	//在雙向鏈表的最後添加元素,由於沒有頭結點和尾結點
	private void lastNode( E e) {
		final Node<E> l = last;
		final Node<E> newNode = new Node<E>(e,l,null);
		last = newNode;
		if(l == null){
			first = newNode;
		}else{
			l.next = last;
		}
		size++;
	}

	private void testIndex(int index)  {
		//拋出運行時異常,是非檢查異常,所以不要trycatch,index >= 0 && index <= size;
		if(!(index>=0&&index<=size)){
			throw new ArrayOutOfBoundsException("位置信息初始化錯誤,大於size");
		}
	}
	
	public int size(){
		return size;
	}
	
	public boolean isEmpty(){
		return size == 0;
	}

	@Override
	public Iterator<E> iterator() {
		return new ListIterator();
	}
	
	//使用內部類,編寫遍歷集合邏輯
	public class ListIterator implements Iterator<E>{
		private Node<E> node = first;
		@Override
		public boolean hasNext() {
//			node = node.next;
			return node != null;
		}

		@Override
		public E next() {
			E val = node.data;
			node = node.next;
			return val;
		}
	}
	
}

下面是測試自己手寫LinkedList代碼

public class TestLinkedList {
	
	public static void main(String[] args) {
		LinkedList<Integer> list = new LinkedList<>();
//		System.out.println(list.size());
		list.add(111);
		list.add(1554);
		list.add(333);
		list.add(88888);
		list.add(262511);
		System.out.println(list.size());
		Integer ai = list.get(2);
		System.out.println(ai);
		
		list.add(1, 66669);
//		System.out.println(list.size());
		System.out.println(list.get(1));
		
		Iterator<Integer> it = list.iterator();
		while(it.hasNext()){
			System.out.print(it.next()+"  ");
		}
	}
}

測試結果

個人理解:理解源碼和數據結構的最好方式,單步調試初步理解,自己重新手寫

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章