1. 程式人生 > >Java源碼--LinkedList源碼概述

Java源碼--LinkedList源碼概述

ray 優勢 array ransient last pan indexof lean 當前

與ArrayList同為List,LinkedList卻展現出不同的特性。作為java.util下的另一重要容器,我們下面來探究一下LinkedList的源碼實現及特性分析。

上篇文章講述到,ArrayList用數組來存儲數據,伴隨數據量的變大,ArrayList動態擴充數組容量
與之不同,LinkedList使用鏈表來存儲數據,因此它在插入/刪除數據方面有著天然的優勢,而在讀取指定位置的元素時,性能卻不及ArrayList速度快

LinkedList存儲元素的變量如下:

transient Node<E> first;

  存儲數據的節點: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; //後節點
} }

 可以看出來,所有元素節點連在一起,構成了雙向鏈表(prev指向前一個元素節點,next指向後一個元素節點)。所有數據,保存在Node的item中。相比於單向鏈表,雙向鏈表提供了兩種操作的方向,因此可以提供更快的遍歷查找速度,更快的插入、刪除元素速度(代價是提升了鏈表維護的難度,以及一點點存儲引用的空間)。

下面看一下LinkedList內部對於雙向鏈表的維護:


在此之前,需要知道的一點:LinkedList額外保存了first和last兩個節點,分別指向首位和末尾,作為雙向鏈表的兩端入口。

內部維護鏈表的一系列函數如下(private、protected):

//用e構造Node,將數據插到首位
private void linkFirst(E e) { final Node<E> f = first; //取得首位節點node final Node<E> newNode = new Node<>(null, e, f); //構造節點,item為e,prev為null,next指向當前的首位f first = newNode; //將first指向newNode,以它作為新的首位 if (f == null) last = newNode; //若之前的首位f不存在,則新的首位節點newNode在作為first的同時,也是last else f.prev = newNode; //若之前的首位f存在,則將f的prev指向新的首位節點newNode size++; modCount++; } //用e構造Node,將數據插到末尾
,原理類似 void linkLast(E e); //將節點插入到指定節點前 void linkBefore(E e, Node<E> succ) { final Node<E> pred = succ.prev; //取得原先succ之前的節點pred,現在需要將newNode插在succ之前,pred之後 final Node<E> newNode = new Node<>(pred, e, succ); //構造內容為e的newNode,prev指向pred,next指向succ succ.prev = newNode; //將succ的prev指向newNode if (pred == null) first = newNode; //若pred為空,則將newNode置為first else pred.next = newNode; //將pred的next指向newNode size++; modCount++; } //將首位first節點從鏈表去掉 private E unlinkFirst(Node<E> f); //將末位last節點從鏈表去掉 private E unlinkLast(Node<E> l); //將任意位置的節點x從鏈表去掉 E unlink(Node<E> x) { //分別考慮prev與next為null和非null的情況,修復prev與next的指向 }

  基於上述鏈表操作函數,LinkedList開放了如下接口(public)

public E getFirst()
{
	//取得first內部的item,返回
}

public E getLast()
{
	//取得last內部的item返回
}

public E removeFirst()
{
	//調用unlinkFirst(Node<E> f), 將first從鏈表移除
}

public E removeLast()
{
	//調用unlinkLast(Node<E> l), 將last從鏈表移除
}

public void addFirst(E e)
{
	//將e插入到first之前
}

public void addLast(E e)
{
	//將e插入到last之後
}

public boolean add(E e)
{
	//調用linkLast(e),將e插入到last之後
}

public boolean remove(Object o)
{
	//從first開始遍歷鏈表,找到o,移除節點
}


public int indexOf(Object o)
{
	//從first開始遍歷節點,找到o,返回index
}

public int lastIndexOf(Object o)
{
	//從last開始反向遍歷鏈表,找到o,移除鏈表
}

public boolean contains(Object o)
{
	//從first開始遍歷鏈表,找到o,返回true;或者找不到o,返回false
}

public boolean addAll(Collection<? extends E> c)
{
	//1. 將集合c轉成數組
	//2. 遍歷數組,對於每個元素,構造node,鏈在last後面
}

  

總結LinkedList用雙向鏈表維護元素,相比於ArrayList提供了快速的插入、移除數據操作的同時,也比單向鏈表的遍歷查找速度更快。但是,相比於ArrayList,LinkedList的查找指定index元素效率低(ArrayList使用數組存儲數據,可以直接依據索引讀取)。

Java源碼--LinkedList源碼概述