4. LinkedList source code analysis

1. Data structure The
Insert picture description here
underlying data structure of LinkedList is a doubly linked list. The overall structure is shown in the figure above. Each node in the linked list can be traced forward or backward.
Each node in the linked list is called a Node. Node has prev and next attributes, which represent the positions of the previous node and the next node, respectively.
first is the head node of the doubly linked list, its previous node is null, last is the tail node of the doubly linked list, and its next node is also null.
When there is no data in the linked list, first and last are the same node, and the front and back points are both null.
Because it is a doubly linked list, as long as the machine memory is powerful enough, there is no size limit.
Source code

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

Source code analysis

  1. The Node node includes three attributes, namely the previous node, its own node, and the next node.
  2. Node node initialization parameter sequence is the previous node, its own node and the next node.

2. Add When adding a
new node, you can choose to append to the head of the linked list or append to the end of the linked list. The add method defaults to append from the end, and the addFirst method is to append from the head. The specific source code is as follows.
Source code

public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable{
    
    
	//从尾部开始追加节点
	void linkLast(E e) {
    
    
	    //尾节点赋值给临时变量
	    final Node<E> l = last;
	    //新建节点,l是新节点的前一个节点,e表示当前新节点,null表示当前新节点的后一个节点
	    final Node<E> newNode = new Node<>(l, e, null);
	    //将新节点追加到尾部
	    last = newNode;
	    //如果链表为空(l和尾节点相等,尾节点为空,链表即为空),头部和尾部是同一个节点且都是新建的节点
	    if (l == null)
	        first = newNode;
	    //否则把前一个节点的下一个节点指向当前节点
	    else
	        l.next = newNode;
	    //修改链表大小和版本
	    size++;
	    modCount++;
	}
	
	//从头部追加
	private void linkFirst(E e) {
    
    
	    //头节点赋值给临时变量
	    final Node<E> f = first;
	    //新建节点,null表示前一个节点,e表示当前新节点,f表示新节点的下一个节点,目前值是头节点的值
	    final Node<E> newNode = new Node<>(null, e, f);
	    //将新节点追加到头部
	    first = newNode;
	    //如果链表为空(f和头节点相等,头节点为空,链表即为空),头部和尾部是同一个节点且都是新建的节点
	    if (f == null)
	        last = newNode;
	    //否则把下一个节点的前一节点指向当前尾节点
	    else
	        f.prev = newNode;
	    //修改链表大小和版本
	    size++;
	    modCount++;
	}
}

Source code analysis
From the source code, we can see that the method of appending nodes at the head and tail is relatively simple, just modify the pointing position, but the former is the prev point of the moving head node, and the latter is the next point of the moving tail node.

3. Query It
is relatively slow to query a certain node in the linked list, and it needs to be searched one by one. The specific source code is as follows.
Source code

public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable{
    
    
	//根据链表索引位置查询节点
	Node<E> node(int index) {
    
    
	    //如果index处于队列的前半部分,从头开始找,size >> 1是size除以2的意思
	    if (index < (size >> 1)) {
    
    
	        Node<E> x = first;
	        for (int i = 0; i < index; i++)
	            x = x.next;
	        return x;
	    } else {
    
    //如果index处于队列的后半部分,从尾部开始找
	        Node<E> x = last;
	        for (int i = size - 1; i > index; i--)
	            x = x.prev;
	        return x;
	    }
	}
}

Source code analysis
It can be found from the source code that LinkedList does not use a loop from beginning to end, but a simple dichotomy. First, see whether the index is in the first half or the second half of the linked list. If it is the first half, start from the beginning and vice versa. In this way, the number of cycles is reduced by at least half and the search efficiency is improved. This idea is worth learning.

4.
Iterator interface can not meet the needs of LinkedList to achieve two-way iterative access (Iterator only supports access from beginning to end), so Java has added an iterative interface ListIterator, which provides forward and backward iteration methods. Such as hasPrevious, previous, previousIndex, hasNext, next and nextIndex. The source code of hasNext, next and remove are as follows.
Source code

public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable{
    
    
	//判断是否有下一个元素
	public boolean hasNext() {
    
    
		//下一个节点的索引小于链表的大小,就存在下一个元素
	    return nextIndex < size;
	}
	 
	//取下一个元素
	public E next() {
    
    
	    //检查期望版本号是否发生变化
	    checkForComodification();
	    //再次检查
	    if (!hasNext())
	        throw new NoSuchElementException();
	    //next是当前节点,在上一次执行next()方法时被赋值
	    lastReturned = next;
	    //next是下一个节点了,为下次迭代做准备
	    next = next.next;
	    nextIndex++;
	    return lastReturned.item;
	}
	
	public void remove() {
    
    
	    checkForComodification();
	    //lastReturned是本次迭代需要删除的值,分空和非空两种情况
	    //lastReturned为空,说明调用者没有主动执行过next()或者previos(),直接报错
	    //lastReturned不为空,是在上次执行next()或者previos()方法时赋的值
	    if (lastReturned == null)
	        throw new IllegalStateException();
	    Node<E> lastNext = lastReturned.next;
	    //删除当前节点
	    unlink(lastReturned);
	    /**
	     * next == lastReturned的场景分析
	     * 从尾到头递归执行,第一次迭代并且要删除最后一个元素的情况下,previous()方法里面设置了lastReturned = next = last,所以next和lastReturned会相等
	     */
	    if (next == lastReturned)
	        //这时候lastReturned是尾节点,lastNext是null,所以next也是null,这样在previous()执行时,发现next是null,就会把尾节点赋值给next
	        next = lastNext;
	    else
	        nextIndex--;
	    lastReturned = null;
	    expectedModCount++;
	}
}

5. Deletion
The method of deleting a node is similar to appending. You can choose to delete from the head or from the tail. The deletion operation will set the value of the node, the front and back pointing nodes to null, and finally the GC will recycle it.
Source code

public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable{
    
    
	//头部删除 
	//f是链表头节点
	private E unlinkFirst(Node<E> f) {
    
    
	    //取出头节点的值作为方法的返回值
	    final E element = f.item;
	    //取出头节点的下一个节点
	    final Node<E> next = f.next;
	    //帮助GC回收头节点
	    f.item = null;
	    f.next = null;
	    //将头节点的下一个节点设置为头节点
	    first = next;
	    //如果next为空,表明链表为空
	    if (next == null)
	        last = null;
	    //链表不为空,将头节点的前一个节点指向null
	    else
	        next.prev = null;
	    //修改链表大小和版本
	    size--;
	    modCount++;
	    return element;
	}
}

Source code analysis

  1. It can be seen from the source code that the node deletion operation of the linked list structure is relatively simple, just modify the points of the front and back nodes. Therefore, the speed of adding and deleting LinkedList is relatively fast.
  2. The tail delete node code is similar to the header delete node code.

Guess you like

Origin blog.csdn.net/Jgx1214/article/details/109064454