[data structure] hand torn single linked list


I hope to communicate with you and learn from each other through my blog. If you have any mistakes, please correct them in the comment area

1, What is a linked list

Sequential tables have defects in space utilization, system consumption and insertion elements. Linked list is the most commonly used dynamic storage method, which overcomes the shortcomings of sequential list.

Linked list is a non continuous and non sequential storage structure on the physical storage unit. The logical order of data elements is realized through the reference link order in the linked list

The linked list consists of a series of nodes (each element in the linked list is called a node), which can be generated dynamically at run time. Each node consists of two parts: one is to store the data field of the data element, and the other is to store the reference field pointing to the next node


There are many linked list structures, including the following 6 cases and 8 combinations

  • Headless, headless
  • Unidirectional and bidirectional
  • Cyclic and non cyclic

In these eight cases, we generally focus on two of them, headless one-way acyclic list and headless two-way acyclic list

2, Hand torn list

The headless one-way acyclic linked list is implemented here

Attribute definition

We need to have linked list nodes and linked list objects, as follows:

Node object

public class Node {
    public int data;
    public Node next;
}

Construction method

public Node(int data) {
	this.data = data;    // Note that this should be used. If data is written directly in it, it is the formal parameter data
	this.next = null;
}

Linked list object

public class MyLinkedList {
    public Node head;
}

Construction method

public MyLinkedList() {
    this.head = null;
}

Implementation of linked list

//Head insert
public void addFirst(int data);
//Tail insertion
public void addLast(int data);
//Insert at any position, and the first data node is subscript 0
public void addIndex(int index,int data);
//Find whether the keyword key is included
public boolean contains(int key);
//Delete the node whose keyword is key for the first time
public void remove(int key);
//Delete all nodes with the value of key
public void removeAllKey(int key);
//Get the length of the single linked list
public int size();
public void display();
public void clear();

Note: when implementing these methods, pay attention to traversing the linked list while loop. The judgment condition should be cur next != Null or cur= null

When inserting or deleting elements, consider boundary conditions and special cases (only one node, empty node, etc.)

Head insert

public void addFirst(int data) {
    Node newNode = new Node(data);
    if (this.head == null) {     // When it is an empty linked list, you only need to make the head point to the node
        head = newNode;        
        return;
    }
    newNode.next = head;
    head = newNode;
}

Tail insertion

Pay attention to special treatment when the linked list is empty If it is not empty, find the tail by traversing the linked list, and then insert it

public void addLast(int data) {
    Node newNode = new Node(data);
    if (head == null) {
        head = newNode;
        return;
    }
    Node cur = head;
    while (cur.next != null) {
        cur = cur.next;
    }
    cur.next = newNode;
}

Get the length of the single linked list

public int size() {
    int count = 0;
    Node cur = this.head;
    while (cur != null) {
        cur = cur.next;
        count++;
    }
    return count;
}

Insert anywhere

Set the first data node as subscript 0. Note that there will be header insertion, tail insertion, illegal subscript, etc

public void addIndex(int index, int data) {
    if (index < 0 || index > this.size()) {
        throw new RuntimeException("index" + ":" + index);
    }
    Node newNode = new Node(data);
    if (index == 0) {    // Head insert
        this.addFirst(data);
        return;
    }
    if (index == this.size()) {   // Tail insertion
        this.addLast(data);
        return;
    }
    Node cur = this.head;
    while (index - 1 != 0) {
        cur = cur.next;
        index--;
    }
    newNode.next = cur.next;
    cur.next = newNode;
}

Find whether the keyword key is included

Traverse the linked list and compare the node data with the key

public boolean contains(int key) {
    Node cur = this.head;
    while (cur != null) {
        if (cur.data == key) {
            return true;
        }
        cur = cur.next;
    }
    return false;
}

Delete the node whose keyword is key for the first time

Traverse the linked list, find the first node with key and delete it. Special cases such as empty linked list and header deletion should be considered

public void remove(int key) {
    if (this.head == null) {
        return;
    }
    if (head.data == key) {   // Header deletion
        head = head.next;
        return;
    }
    Node cur = this.head;
    while (cur.next != null) {
        if (cur.next.data == key) {
            break;
        }
        cur = cur.next;
    }
    if (cur.next != null) {
        cur.next = cur.next.next;
    }
}

Print single linked list

public void display() {
    Node cur = this.head;
    while (cur != null) {
        System.out.print(cur.data + "->");
        cur = cur.next;
    }
    System.out.print("null");
}

Empty linked list

After using the linked list, use the clear() method to prevent memory leakage (check the process number jps, redirect jmap - histo: Live 6666 > e: \ Niubi. Txt)

public void clear() {
    this.head = null;
}

Delete all nodes with the value of key

Note: 1 When does prev jump back? The first node should not be judged at the beginning, but the first node should be judged after all the subsequent nodes are deleted

public void removeAll(int key) {
    if (this.head == null) {
        return;
    }
    Node prev = this.head;
    Node cur = this.head.next;
    while (cur != null) {
        if (cur.data == key) {
            prev.next = cur.next;
            cur = cur.next;
        } else {
            prev = cur;
            cur = cur.next;      // Not key, cur and prev jump back
        }
    }
    if (this.head.data == key) {
        this.head = this.head.next;
    }
}

2. Two way linked list

Here, take the bidirectional headless acyclic linked list as an example, as shown in the following figure:

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-4bvzi6qi-1641391981418) (C: \ users \ lycre \ appdata \ roaming \ typora \ typora user images \ image-20220105182248704. PNG)]

Attribute definition

The node object and construction method are the same as that of single line table

Linked list object

The linked list object has one more tail attribute, which points to the tail node of the linked list

public class MyLinkedList{
    public Node head;
    public Node tail;
}

Construction method

Nonparametric construction method

public MyLinkedList() {
    this.head = null;
    this.tail = null;
}

Implementation of linked list

//Head insertion
public void addFirst(int data);
//Tail interpolation
public void addLast(int data);
//Insert at any position, and the first data node is subscript 0
public void addIndex(int index,int data);
//Find whether the keyword key is included
public boolean contains(int key);
//Delete the node whose keyword is key for the first time
public void remove(int key);
//Delete all nodes with the value of key
public void removeAllKey(int key);
//Get the length of the linked list
public int size();
//Print linked list
public void display();
//Clear the linked list and free up memory
public void clear();

Head insert

Pay attention to the empty linked list in the process of header insertion

public void addFirst(int data) {
    Node newNode = new Node(data);
    if (this.head == null) {    // When the linked list is empty
        this.head = newNode;
        this.tail = newNode;
    } else {
        newNode.next = this.head;
        this.head.prev = newNode;
        this.head = newNode;
    }
}

Tail insertion

public void addLast(int data) {
    Node newNode = new Node(data);
    if (this.head == null) {   // The linked list is empty
        this.head = newNode;
        this.tail = newNode;
    } else {
        newNode.prev = tail;
        this.tail.next = newNode;
        this.tail = newNode;
    }
}

Get the length of the linked list

public int size() {
    int count = 0;
    Node cur = this.head;
    while (cur != null) {
        count++;
        cur = cur.next;
    }
    return count;
}

Insert anywhere

There are many situations to consider when inserting elements at any position. We should list all possible situations before writing to avoid ignoring some situations

Pay attention to judge the validity of index

public void addIndex(int index,int data) {
    if (index < 0 || index > this.size()) {
        throw new RuntimeException("index : "  + index);
    }
    Node newNode = new Node(data);
    if (index == 0) {
        if (this.head == null) {   // Head insert
            this.head = newNode;
            this.tail = newNode;
        } else {
            newNode.next = this.head;
            this.head.prev = newNode;
            this.head = newNode;
        }
    } else if (index == this.size()) {   // Tail insertion
        newNode.prev = this.tail;
        this.tail.next = newNode;
        this.tail = newNode;
    } else {
        Node cur = this.head;
        while (index != 0) {
            cur = cur.next;
            index--;
        }
        Node prevNode = cur.prev;
        newNode.next = cur;
        newNode.prev = prevNode;
        prevNode.next = newNode;
        cur.prev = newNode;
    }
}

Find whether the keyword key is included

Directly traverse the linked list and compare them one by one

public boolean contains(int key) {
    Node cur = this.head;
    while (cur != null) {
        if (cur.data == key) {
            return true;
        }
    }
    return false;
}

Delete the node whose keyword is key for the first time

It involves head deletion, tail deletion, empty linked list, etc

public void remove(int key) {
    if (this.head == null) {
        return;
    }
    Node cur = this.head;
    while (cur != null) {        // Find the first node with key
        if (cur.data == key) {
            break;
        }
        cur = cur.next;
    } 
    if (cur == null) {
        return;          //No, go straight back
    }
    if (cur == this.head) {       // Header deletion
        this.head = head.next;
        this.head.prev = null;  
        return;
    }
    if (cur == this.tail) {     // Tail deletion
        cur.prev.next = null;
        this.tail = cur.prev;
        return;
    }
    Node prevNode = cur.prev;
    Node nextNode = cur.next;
    prevNode.next = nextNode;
    nextNode.prev = prevNode;
}

Delete all nodes with the value of key

public void removeAllKey(int key) {
    if (this.head == null) {
        return;
    }
    Node prevNode = this.head;
    Node cur = this.head.next;
    while (cur != null) {
        if (cur.data == key) {
            prevNode.next = cur.next;
            cur = cur.next;
            if (cur == null) {
                this.tail = prevNode;     // The last node value is key
            } else {
                cur.prev = prevNode;
            }
        } else {
            cur = cur.next;
            prevNode = prevNode.next;
        }
    }
    if (this.head.data == key) {
        this.head = this.head.next;
        if (this.head == null) {
            this.tail = null;      // Note that when all elements in the linked list are key s, not only the head but also the tail should be determined at the end
            return;
        }
        this.head.prev = null;
    }
}

Print linked list

public void display() {
    Node cur = this.head;
    while (cur != null) {
        System.out.print(cur.data + "->");
        cur = cur.next;
    }
    System.out.print("null");
}

Clear the linked list and free up memory

public void clear() {
    if (this.head == null) {
        return;
    }
    Node cur = this.head;
    Node nextNode;
    while (cur != null) {
        nextNode = cur.next;
        cur.prev = null;
        cur.next = null;
        cur = nextNode;
    }
    this.tail = null;
}

Note that there is a big difference between emptying a two-way linked list and a one-way linked list. You can't directly set the head to null, because the later nodes also save the references of the previous nodes, so we should empty the next field and prev field of all nodes

Welcome to pay attention!!!

Learn and communicate together!!!

Let's finish the programming!!!

--------------It's not easy to organize. Please support the third company------------------

Keywords: Java Algorithm data structure linked list

Added by saariko on Tue, 25 Jan 2022 06:02:21 +0200