3.Java SDK源码分析系列笔记-LinkedList

1. 是什么

底层由双向链表实现的顺序表
有序、可以重复

2. 如何使用

public class LinkedListTest {     public static void main(String[] args)     {         LinkedList<String> list = new LinkedList<>();         list.add("1");         list.add("2");         list.addFirst("3");         list.addLast("4");         System.out.println(list);         list.remove(0);         list.remove("2");         list.remove();         list.removeFirst();         list.removeLast();       } }  

3. 原理分析

3.1. uml

3.Java SDK源码分析系列笔记-LinkedList
可以看出LinkedList是个List、双端队列、可序列化、可克隆

3.2. 构造方法

由头节点、尾节点、长度构成

public class LinkedList<E>     extends AbstractSequentialList<E>//提供了List的骨架实现     implements List<E>/*List接口*/, Deque<E>/*双端队列*/, Cloneable, java.io.Serializable {      //属性     transient int size = 0;//长度     transient Node<E> first;//头节点     transient Node<E> last;//尾节点      //构造方法     public LinkedList() {     } } 

3.2.1. 队列的节点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;     } } 

结构如下图:
3.Java SDK源码分析系列笔记-LinkedList

3.3. add方法

  • O(1)
public boolean add(E e) {     //调用linkLast方法     linkLast(e);     return true; }  

3.3.1. 插入到链表尾部

  • linkLast
void linkLast(E e) { 	//保存尾节点     final Node<E> l = last;     //构造新的节点,prev指向last节点     final Node<E> newNode = new Node<>(l, e, null);     //把尾节点更新为新的节点     last = newNode;     //如果原来的尾节点为空,那么是第一个节点。此时更新first为新节点     if (l == null)         first = newNode;     else 	//否则更新尾节点的next为新的节点         l.next = newNode;     size++;     modCount++; } 

3.3.2. 构造新节点【prev指向尾节点,next为null】

//保存尾节点 final Node<E> l = last; //构造新的节点,prev指向last节点 final Node<E> newNode = new Node<>(l, e, null); 

3.3.3. 更新尾节点

//如果原来的尾节点为空,那么是第一个节点。此时更新first为新节点 if (l == null)     first = newNode; else //否则更新尾节点的next为新的节点     l.next = newNode; 

3.3.4. 更新size

size++; 

3.4. addLast方法

  • O(1)
public void addLast(E e) { 	//调用linkLast     linkLast(e); } 
  • linkLast
    参考add方法

3.5. addFirst方法

  • O(1)
public void addFirst(E e) { 	//简单的调用linkFirst     linkFirst(e); } 

3.5.1. 头部插入节点

  • linkFirst
 private void linkFirst(E e) { 	//先保存原头节点     final Node<E> f = first;     //新建节点,next指向原头节点     final Node<E> newNode = new Node<>(null, e, f);     //更新头节点为新的节点     first = newNode;     //如果原头节点为空,那么是第一个元素,更新last节点为新的节点     if (f == null)         last = newNode;     else     //否则更新原头节点的prev为新的节点         f.prev = newNode;              size++;     modCount++; } 

3.5.2. 构造新节点【prev指向null,next指向头节点】

//先保存原头节点 final Node<E> f = first; //新建节点,next指向原头节点 final Node<E> newNode = new Node<>(null, e, f); 

3.5.3. 更新头节点

//如果原头节点为空,那么是第一个元素,更新last节点为新的节点 if (f == null)     last = newNode; else //否则更新原头节点的prev为新的节点     f.prev = newNode; 

3.5.4. 更新size

size++; 

3.6. remove方法【根据下标删除】

  • O(N)

  • 修改这个元素的前后元素的next和prev指针

public E remove(int index) { 		//检查是否越界         checkElementIndex(index);     	//根据下标找到相应的节点,并把这个节点删除         return unlink(node(index));     }      

3.6.1. 遍历找到这个位置的元素

  • node
 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;     } }   

3.6.2. 更新该节点前后节点的指针

E unlink(Node<E> x) {     // assert x != null;     //首先保存当前节点的prev,next,和item值     final E element = x.item;     final Node<E> next = x.next;     final Node<E> prev = x.prev;  	//更新prev     if (prev == null) {     	//前一个节点为空(说明当前节点是头节点),那么把first指向当前节点的下一个节点即可         first = next;     } else {     	//前一个节点的next指向当前节点的下一个节点         prev.next = next;         //help gc         x.prev = null;     }  	//更新next     if (next == null) {     	//后一个节点为空(说明当前节点是尾节点),那么把last指向当前节点的上一个节点即可         last = prev;     } else {     	//后一个节点的prev指向当前节点的上一个节点         next.prev = prev;         //help gc         x.next = null;     }  	//help gc     x.item = null;     size--;//更新size     modCount++;     return element; }  

3.7. remove方法【按照元素删除】

  • O(N)
public boolean remove(Object o) { 	//==null     if (o == null) {     	//遍历找到node         for (Node<E> x = first; x != null; x = x.next) {             if (x.item == null) {                 unlink(x);                 return true;             }         }     //equals     } else {     	//遍历找到node         for (Node<E> x = first; x != null; x = x.next) {             if (o.equals(x.item)) {                 unlink(x);                 return true;             }         }     }     return false; } 

3.7.1. 遍历找到这个元素

for (Node<E> x = first; x != null; x = x.next) {     //... } 

3.7.2. 更新该节点前后节点的指针

3.8. remove方法【无参】

  • O(1)
public E remove() { 	//简单调用removeFirst     return removeFirst(); } 

3.8.1. 删除头部节点

  • removeFirst
 public E removeFirst() { 	//头节点     final Node<E> f = first;     if (f == null)     	//为null直接抛出异常         throw new NoSuchElementException();     //调用unlinkFirst从链表删除头节点     return unlinkFirst(f); }   

3.8.2. 把原来头节点的next节点更新为头节点

  • unlinkFirst
  private E unlinkFirst(Node<E> f) {     // assert f == first && f != null;     //保存item,next     final E element = f.item;     final Node<E> next = f.next; 	 	// help GC         f.item = null;     f.next = null;           //first直接指向头节点的next     first = next;     //如果头节点的next为空,说明链表中只有一个节点     if (next == null)     	//更新last指向null         last = null;     else     	//否则更新头节点的next节点的prev指针         next.prev = null;     size--;     modCount++;     return element; } 

3.9. removeLast方法

  • O(1)
public E removeLast() {         final Node<E> l = last;         if (l == null)             throw new NoSuchElementException();         return unlinkLast(l);     } 

3.9.1. 把原来尾节点的prev节点更新为尾节点

  • unlinkLast
private E unlinkLast(Node<E> l) {     // assert l == last && l != null;     //保存尾节点的item值和prev     final E element = l.item;     final Node<E> prev = l.prev;     // help GC     l.item = null;     l.prev = null;     //更新last为原尾节点的prev     last = prev;     //只有一个元素     if (prev == null)         first = null;     else         prev.next = null;     size--;     modCount++;     return element; } 

发表评论

评论已关闭。

相关文章