Java手寫LinkedList 應用資料結構之雙向連結串列
阿新 • • 發佈:2018-12-13
作為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()+" "); } } }
測試結果
個人理解:理解原始碼和資料結構的最好方式,單步除錯初步理解,自己重新手寫