LinkedList详解,看这篇就够了
文章推薦
- 精選java等全套學習資源
- 精選java電子圖書資源
- 精選大數據學習資源
- java項目練習精選
##屬性
LinkedList 提供了以下三個成員變量。size,first,last。
transient int size = 0;transient Node<E> first;transient Node<E> last;其中 size 為 LinkedList 的大小,first 和 last 分別為鏈表的頭結點和尾節點。Node 為節點對象。
private static class Node<E> {E item;Node<E> next;Node<E> prev;Node(Node<E> prev, E element, Node<E> next) {this.item = element;this.next = next;this.prev = prev;} }Node 是 LInkedList 的內部類,定義了存儲的數據元素,前一個節點和后一個節點,典型的雙鏈表結構。
##構造方法
public LinkedList() {} public LinkedList(Collection<? extends E> c) {this();addAll(c); }LinkedList 提供了兩個構造方法:LinkedList() 和 LinkedList(Collection<? extends E> c)。
LinkedList() 僅僅構造一個空的列表,沒有任何元素。size = 0。first 和 last 都為 null。
后一個構造方法構造一個包含指定 Collection 中所有元素的列表,該構造方法首先會調用空的構造方法,然后通過 addAll() 的方式把 Collection 中的所有元素添加進去。
- 調用 addAll() 方法,傳入當前的節點個數 size,此時 size 為
- 檢查 index 是否越界
- 將 collection 轉換成數組
- 遍歷數組,將數組里面的元素創建為節點,并按照順序連起來。
- 修改當前的節點個數 size 的值
- 操作次數 modCount 自增 1.
##add 操作
添加元素到鏈表末尾
public boolean add(E e) {linkLast(e);return true; }void linkLast(E e) {final Node<E> l = last;final Node<E> newNode = new Node<>(l, e, null);last = newNode;if (l == null)first = newNode;elsel.next = newNode;size++;modCount++; }add 方法直接調用了 linkLast 方法,而 linkLast 方法是不對外開放的。該方法做了三件事情,新增一個節點,改變其前后引用,將 size 和 modCount 自增 1。其中 modCount 是記錄對集合操作的次數。
在指定的位置插入元素
首先檢查下標是否越界,然后判斷如果 index == size 則添加到末尾,否則將該元素插入的 index 的位置。其中 node(index) 是獲取 index 位置的節點,linkBefore 負責把元素 e 插入到 succ 之前。
Node<E> node(int index) {// assert isElementIndex(index);if (index < (size >> 1)) {Node<E> x = first;for (int i = 0; i < index; i++)x = x.next;return x;} else {Node<E> x = last;for (int i = size - 1; i > index; i--)x = x.prev;return x;} }可以看出 node() 方法這里寫的還是挺贊的,不是傻乎乎的從頭到尾或者從尾到頭遍歷鏈表,而是將 index 與 當前鏈表的一半做對比,比一半小從頭遍歷,比一半大從后遍歷。對于數據量很大時能省下不少時間。
##get 操作
很簡單,首先獲取節點,然后返回節點的數據即可。
public E get(int index) {checkElementIndex(index);return node(index).item; }##remove 操作
移除指定位置的元素
public E remove(int index) {checkElementIndex(index);return unlink(node(index)); }E unlink(Node<E> x) {// assert x != null;final E element = x.item;final Node<E> next = x.next;final Node<E> prev = x.prev;if (prev == null) {first = next; // 如果移除的是頭節點,那么頭結點后移} else {prev.next = next;x.prev = null; // 釋放節點的前一個元素}if (next == null) {last = prev; // 如果移除的是尾節點,尾結點前移} else {next.prev = prev;x.next = null; // 釋放節點的后一個元素}x.item = null; // 釋放節點數據size--;modCount++;return element; }先檢查下標是否越界,然后調用 unlink 釋放節點。
移除指定元素
判斷要移除的元素是否為 null,然后在遍歷鏈表,找到鈣元素第一次出現的位置,移除并返回 true。
像其他的常用方法如:getFirst, getLast, removeFirst, removeLast, addFirst, addLast 等都很簡單,掃一眼源碼就能懂,我這里就不寫了。
迭代器
LInkedList 的 iterator() 方法是在其父類 AbstractSequentialList 中定義的,最終一路 debug 到 LinkedList 類這里。其中 index 為 零。
public ListIterator<E> listIterator(int index) {checkPositionIndex(index);return new ListItr(index); }我們來看看 ListItr。
private Node<E> lastReturned;private Node<E> next;private int nextIndex;private int expectedModCount = modCount;ListItr(int index) {// assert isPositionIndex(index);next = (index == size) ? null : node(index);nextIndex = index;}public boolean hasNext() {return nextIndex < size;}public E next() {checkForComodification();if (!hasNext())throw new NoSuchElementException();lastReturned = next;next = next.next;nextIndex++;return lastReturned.item;}final void checkForComodification() {if (modCount != expectedModCount)throw new ConcurrentModificationException();} }篇幅有限 ,我就只貼主要代碼了。由源碼可以看出初始化 ListItr 時,將 nextIndex 指向 index, 也就是零。如果該集合為空,那么 index == size 為 true,next 指向 null,否則 next 指向下標為零的元素,也就是第一個。
hasNext 直接返回 nextIndex < size 簡單明了。下面看看 next 方法,首先檢查 expectedModCount 與 modCount 是否相等,看似無關緊要的代碼保證了集合在迭代過程中不被修改[包括新增刪除節點等]。然后將 lastReturned 指向 next,next 后移一個節點,nextIndex 自增 1,并返回 lastReturned 節點的元素。
###總結
1、從源碼可以看出 LinkedList 是基于鏈表實現的。如下圖:
2、在查找和刪除某元素時,區分該元素為 null和不為 null 兩種情況來處理,LinkedList 中允許元素為 null。
3、基于鏈表實現不存在擴容問題。
4、查找時先判斷該節點位于前半部分還是后半部分,加快了速度
5、因為基于鏈表,所以插入刪除極快,查找比較慢。
6、實現了棧和隊列的相關方法,所以可作為棧,隊列,雙端隊列來用。
作者:coderlmm
鏈接:https://juejin.im/post/5a90c2fd6fb9a06361089023
總結
以上是生活随笔為你收集整理的LinkedList详解,看这篇就够了的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java网络编程(一)
- 下一篇: Java7 HashMap详解