Java collection framework - LinkedList source code

Posted by wolfan on Thu, 28 May 2020 11:35:01 +0200

Source code analysis of LinkedList

LinkedList's data node is a two-way linked list. Because it is a linked list structure, LinkedList is more suitable for scenarios with frequent addition and deletion but infrequent query and modification. Its application scenario is somewhat opposite to ArrayList.

Structure of LinkedList

1. Implemented the List interface: all the methods in the List interface can be used.
2. The clonable interface is implemented, so LinkedList supports cloning, but only shallow cloning. In the LinkedList class, the internal class Node is not cloned, only the clone method in the Object class is called for cloning.
3. The Serializable interface is implemented, so LinkedList supports serialization.
4. The Deque interface is implemented, and the optional operation of Deque is realized.
5. Inherited AbstractSequentialList abstract class, when traversing, it is recommended to use iterator for traversal.

Source code explanation in LinkedList:

1, The core component of LinkedList source code: the node used to store data is designed as an internal class in LinkedList

/**
    Internal class for storing data, used to create nodes
*/
private static class Node<E> {
    E item;
    Node<E> next;
    Node<E> prev;

    //Internal class construction method, passing in the pre parameter node, the element to be added and the post node
    Node(Node<E> prev,E element,Node<E> next){
        this.item = element;
        this.next = next;
        this.prev = prev;
    }
}

1, Fields

1. int size = 0: record the actual number of stored elements in the LinkedList collection container
2. Node < E > First: record the head node in the bidirectional linked list
3. Node < E > last: record the tail nodes in the two-way linked list

2, Construction method

There are only two construction methods for LinkedList. Compared with ArrayList, there is no construction method for initializing capacity. This is mainly because ArrayList is an array, and the incoming initial capacity is to create an array with initial length, while LinkedList is a linked list structure. Each new addition is on the link behind the original node, so there is no constructor for initializing capacity

1,Nonparametric structure

/**
Nonparametric construction method
*/
public LinkedList(){}
/**
Parameter constructor: passing a container as a parameter
*/
public LinkedList(Collection&lt;? extends E&gt; c){
//Call parameterless constructor first
this();
//Then call addAll(c); add all the elements in the incoming parameter set to the newly created LinkedList container.
addAll(c);
}

3, LinkedList common method implementation

1. Add element

1) Add a single element:add(E e)

/**
Method added
*/
public boolean add(E e){
//Call the method added at the end
linkLast(e);
return true;
}
//Add in last method
void linkLast(E e){
//To add the added e element at the end, first record the original last element and point to the
final Node&lt;E&gt; l = last;
//Create a new node and encapsulate the E element. The front node is l, the element is e, and the back element is not null
final Node&lt;E&gt; newNode = new Node&lt;&gt;(l,e,null);
//Set the new node as the last node
last = newNode;
//Judge whether the original tail node l is tail null
if(l == null){
//If it is null, it means there is no element, and the new node is the head node
first = newNode;
}else{
//Otherwise, the next of the original tail Phase l will point to the new node
l.next = newNode;
}
//Increase the number of actual elements by 1
size++;
//Operation times plus 1
modCount++;
}

2) Add an element at the end

/**
Add an element at the end of the list
*/
public void addLast(E e){
//Directly call linklast (e e e), which adds elements at the end. The source code has been described above and will not be repeated.
linkLast(E e);
}

3) Add element in first place

/**
Add elements in the LinkedList container at the first location
*/
public void addFirst(E e){
//Call linkFirst(e) directly;
linkFirst(e);
}
//How to add elements in the first place
private void linkFirst(E e){
//Record primitive element
final Node&lt;E&gt; f = first;
//Create a new node. The previous element is null, and next points to the original header element f
final Node&lt;E&gt; newNode = new Node&lt;&gt;(null,e,f);
//Set the header node to newNode
first = newNode;
//Determine whether the original header node f is null,
if(f == null){
//If it is null, both the head node and the tail node should be newNode
last = newNode;
}else{
//Otherwise, the front node of the original head node sets the tail newNode
f.prev = newNode;
}
//Increase the number of actual elements by 1;
size++;
//Operation times increased by 1
modCount++;
}

4) Add element at specified index

/**
Add an element at the location specified for the lead out
*/
public void add(int index,E element){
//Judge whether the index parameter passed in is legal
checkPositionIndex(index);
//Judge whether the index passed in is the last position, and compare it with size
if(index == size){
//Add elements directly to the tail
linkLast(element);
}else{
//Otherwise, add at the specified index location
linkBefore(element,node(index));
}
}
//The method of adding elements at the execution index position, adding elements before non empty succ nodes.
void linkBefore(E element,Node&lt;E&gt; succ){
//Declare a node, temporarily record the front node of the succ node, because the new node needs to be added in front of the succ node
final Node&lt;E&gt; pred = succ.prev;
//Create a new node, and the front of the new node points to pred, and the back node points to the current node succ
final Node&lt;E&gt; newNode = new Node&lt;E&gt;(prev,element,succ);
//Judge whether the original node pred pointed by succ is empty
if(pred == null){
//If it is empty, then there is no element in front of it, then the new node is the head node
first = newNode;
}else{
//Otherwise, the next of the previous node pred of the recorded succ points to the new node newNode
pred.next = newNode;
}
//Increase the number of actual elements by 1
size++;
//Increase the number of actual operations by 1
modCount++:
}
//Calculate the node elements to insert according to the incoming index
Node&lt;E&gt; node(int index){
//In the LinkedList collection container, the traversal elements are optimized to determine whether the incoming index index is near the end node or the head node
if(index &lt; (size &gt;&gt;1)){
//Traverse from the beginning to the index
Node&lt;E&gt; x = first;
for(int i = 0;i &lt; index;i++){
x = x.next;
}
return x;
}else{
//Traverse from the tail to the front
Node&lt;E&gt; x = last;
for(int i = size - 1;i &gt; index;i--){
x = x.prev;
}
return x;
}
}

2. Method of deletion
1) Delete the specified element in the LinkedList collection container

public boolean remove(Object obj){
//Determine whether the passed in element obj has a null suffix
if(obj == null){
//Traverse all nodes in LinkList
for(Node&lt;E&gt; x = first;x!= null;x = x.next){
//If the element value of the x node is equal to null, delete the node
if(x.item == null){
//Delete Vertex 
unlink(x);
return true;
}
}
}else{
//Otherwise, the value of the passed in element obj is not null
for(Node&lt;E&gt; x = first;x != null;x = x.next){
//The difference between null and not is here
if(obj.equals(x.item)){
//Delete this node
unlink(x);
return true;
}
}
}
//Otherwise, return false
return false;
}
//How to delete a node
E unlink(Node&lt;E&gt; x){
//Define a variable to record the current value of the node to be deleted, because it will return to
final E element = x.item;
//Define a node variable to record the post node of the node
final Node&lt;E&gt; next = x.next;
//Define a node variable to record the previous node of the node
final Node&lt;E&gt; prev = x.prev;
//Judge whether the front node of node x to be deleted is null. If it is null, the next of the back node of node x to be deleted is set as the head node
if(prev == null){
first = next; 
}else{
//Otherwise, connect the front node and the back node of node x to be deleted
prev.next = next;
//The former node of node x to be deleted is set to null, which is equivalent to disconnection
x.prev = null;
}
//Determine whether the next node of the node to be deleted is null
if(next == null){
//Directly set the node to be deleted as the tail node
last = prev;
}else{
//Otherwise, prev of the back node of the node x to be deleted points to the front node of the node to be deleted
next.prev = prev;
x.next = null;
}
//Set the element value of the node to be deleted to null
x.item = null;
//Actual length reduced by 1
size--;
//Operation increase 1
modCount++;
//Return the original element value of the node to be deleted
return element;
}

2) Empty all elements in the LinkedList collection frame

/**
*   Empty all elements in the LinkedList collection
*/
public void clear(){
//Traverse all elements in the LinkedList collection container and set all nodes to null
for(Node&lt;E&gt; x = first;x != null){
Node&lt;E&gt; next = x.next();
x.item = null;
x.next = null;
x.prev = null;
}
//Set both the head node and the tail node to null
first = last = null;
//Actual element set to 0
size = 0;
//Operation times increased by 1
modCount++:
}

3) Delete node at specified index location

/**
*   Delete elements based on the index location passed in
*/
public E remove(int index){
//Verify that the user name is legal
checkElementIndex(index);
//Directly return to the deletion method, which has been described above, so it will not be analyzed repeatedly
return unlink(node(index));
}

3. Query elements
1) Query the elements in the location according to the index

/**
*   Query the element value of the location according to the index location
*/
public E get(int index){
//Verify that the user name is legal
checkElementIndex(index);
//Return the element value of the node. The use of node(index) has been described above and will not be repeated.
return node(index).item;
}

4. Modify node element
1) Set element values based on index location

/**
*  Set index value according to index value
*/
public E set(int index,E element){
//Check whether the index position is legal
checkElementIndex(index);
//Get the node according to the index
Node&lt;E&gt; x = node(index);
//Define variables to record element values of the original node
E oldVol = x.item;
//Replace the original element value with the passed in element value
x.item = element;
//Return the element value of the original node
return oldVol;
}

Topics: Java