Sorting and understanding of Java collection framework (addition and deletion analysis of Linkedlist two-way linked list)

Analysis of adding and deleting Linkedlist bidirectional linked list

Start with a new Linkedlist

        LinkedList linkedList = new LinkedList<>();

Enter the source code:

    public LinkedList() {
    }

. . . . . It seems that creating a Linkedlist does nothing. Let's take a look at some of its default configurations first

transient int size = 0;

    /**
     * Pointer to first node.
     * Invariant: (first == null && last == null) ||
     *            (first.prev == null && first.item != null)
     */
    transient Node<E> first;

    /**
     * Pointer to last node.
     * Invariant: (first == null && last == null) ||
     *            (last.next == null && last.item != null)
     */
    transient Node<E> last;

The first is size, which is 0 by default, followed by the first node and the last node, which are null by default.
Here is the source code of 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;
        }
    }

It can be seen that element e is prev of the previous node and next of the latter node
Standard two-way linked list

Then let's add and see

  linkedList.add(1);

Enter the source code of the add method:

    public boolean add(E e) {
        linkLast(e);
        return true;
    }

It's still very simple, and then go to the source code of linkLast
As can be seen from the name linkLast, Linkedlist uses tail interpolation to insert new elements by default
Then we go to the linkLast method

    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;
        else
            l.next = newNode;
        size++;
        modCount++;
    }

First, make the local variable l equal to last, that is, the tail node. Note that this is the first time to add, and the tail node is now null.
Then continue to create a new variable newNode and construct it using the construction method
newNode node the former node is the original last node, and the latter node is null, e is the incoming element
Next, let last = newNode. Because the tail interpolation method is used, the last node is the newNode node just created
Then enter judgment,
When is the original last node empty?
When there is only one node, the node itself belongs to both the first node and the tail node.
Only when there is no node can the variable l be empty. At this time, it can be judged that there is only one element
Therefore, the node newNode is assigned to the first node.
Note: if there is not only one node, enter else, that is, the next node of the original tail node points to the currently created newNode
At this point, the addition of Linkedlist is over.

Deleting Linkedlist

In fact, there's nothing to talk about, but since we want to talk about it, let's talk about it together.
First, look at the source code:

    public boolean remove(Object o) {
        if (o == null) {
            for (Node<E> x = first; x != null; x = x.next) {
                if (x.item == null) {
                    unlink(x);
                    return true;
                }
            }
        } else {
            for (Node<E> x = first; x != null; x = x.next) {
                if (o.equals(x.item)) {
                    unlink(x);
                    return true;
                }
            }
        }
        return false;
    }

When an object is passed in, it is judged first
Since the operation of this judgment is the same, we won't talk about it
If the variable o is equal to null, or O is not equal to null
Use the for loop to traverse from the first node,
The termination condition is x==null (because the next node of the tail node of the two-way linked list is null)
Let x=x.next every time, that is, a node by node query, and the next node query pointed by each node
Then, if the queried value is equal to null (this is the first judgment)
Or equal to the passed in variable o (second judgment)
unlink is executed, that is, the delete method

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

It looks a little long, but it's actually occupied by some if judgments
Let's start the analysis
First, it is still the assignment. Note that the node x queried by the previous operation is passed in
Then assign the data with element x
Next is the next node of x
prev is the last node of x
Then it's still judgment
If prev is empty, what does it prove?
There's nothing more advanced than him. Of course, it's the head node
That x is the node we want to delete
So his next node now begins to accept the important task of the organization and become the first node
What if the node to be deleted is not the first node?
Then connect the node after the node in front of it to the node after the deleted node
It sounds a little awkward, so draw a picture
The double arrow of the line indicates that it is bidirectional
Connect the following node of the previous node to the following node of the deleted node
In this way, it becomes

Now the first node does not point to the node to be deleted, but directly points to the third node
At the same time, to delete the node itself, you need to point to the previous node, which is not needed now, so the line is deleted and directly point to null.

Then we have to perform the second judgment

        if (next == null) {
            last = prev;
        } else {
            next.prev = prev;
            x.next = null;
        }

Still, if the node to be deleted is null
Then prove that this is the tail node
Then it's ok to directly turn the previous node of this node into the tail node, isn't it
Otherwise, it will be
Connect the previous node of the next node to the previous node
At the same time, it points itself to the next node and makes it null.
It's still drawing

At this time, we find that deleting this node does not need to be considered
It has been isolated

        x.item = null;
        size--;
        modCount++;
        return element;

Therefore, leave it blank directly
Then subtract size
You can return
The element returned here cannot be used when directly inputting elements for deletion
It is only useful when you enter a subscript for deletion
Yes, Linkedlist has subscripts
Of course, Linkedlist is a linked list, not an array
So his subscript is actually just convenient for binary search
For example, if the total length is 10
If you enter get (3)
It will be judged that it is less than 5, so it will traverse from the first node
If it is greater than five, if it is 7,
Then it will traverse from the tail node

summary

That's all for the addition and deletion analysis of Linkedlist. The data structure of linked list is still a basic knowledge point,
It's not difficult in essence. If there is any mistake, you are welcome to put it forward and I will correct it (if I can understand the mistake, I'll do it)

Tags: Java data structure linked list LinkedList

Posted on Fri, 10 Sep 2021 21:42:00 -0400 by TouranMan