[Java data structure] understood and implemented through Java -- headless bidirectional linked list

[preface] in< Understanding and implementation through Java -- sequence table and single chain table >In this article, we have finished the sequence list and single linked list, and then the two-way linked list. In fact, it is very similar to the single linked list. What we need to pay attention to is some small details

🍉 Headless bidirectional linked list

🌵 Concept and structure of double linked list

[why is a double linked list introduced?]
  there is only one pointer to its successor in the node of the single linked list, so that when the single linked list wants to access the precursor node of a node, it can only traverse from the beginning. The complexity of accessing the successor node is O(1), and the complexity of accessing the precursor node is O(n). In order to overcome the above shortcomings, a double linked list is introduced.
  there are two pointers prev and next in the node of the double linked list, pointing to the predecessor node and the successor node respectively.

🍌 Implementation of headless bidirectional acyclic linked list interface (notes are very detailed, I 👴👴 Can understand)

First write two classes, one is the linked list class (including a variable head node, a variable tail node and an interface for implementing various functions. Because it is a headless linked list, the head node and tail node are variable), and the other is the node class (the member attributes include value, prev (predecessor) and next (successor))

The following interfaces are written in the linked list class. Because the linked list is an object, we want to realize all the functions of a linked list object

🍈 Print double linked list

Printing a linked list is actually similar to printing a sequential list. It's good to traverse the linked list, but pay attention to one point. Here, you need to introduce a local variable cur to traverse instead of the head node, because the head node is fixed before adding or deleting nodes. Don't let the head node change

//Print double linked list
   public void display() {
       //The printing method is the same as that of single linked list
       ListNode cur = this.head;//The temporary variable cur is used to replace the head node traversal
       while (cur != null){
           System.out.print(cur.val+" ");
           cur = cur.next;//Go back in turn
       }
       System.out.println();
   }

🍈 Head insertion

As the name suggests, the header insertion method is to insert a node from the header to make the newly created node a new header node. Here, we need to consider an additional point, that is, whether the header node exists (whether the linked list is empty), (note that we should not only set the back driver, but also pay attention to the front driver, which has one more front driver node than the single linked list)

//Head insertion
   public void addFirst(int data) {
       ListNode node = new ListNode(data);//Create a new node to store the data to be inserted
       if (this.head==null){//Judge whether the head node is empty. If the head node is empty, the linked list is empty
           //Head node null belongs to the first insertion. Directly point the head node and tail node to the insertion node
           this.head=node;
           this.last=node;
       }else{//If not the first time
           node.next=this.head;//The original head node is changed into the back drive of the newly inserted node to realize head insertion
           head.prev=node;//Then the newly inserted node becomes the precursor of the original head node
           this.head=node;//Finally, set the newly inserted node as the head node
       }
   }

🍈 Tail insertion

The tail insertion method is similar to the head insertion method. We must first judge whether the linked list is empty (judge whether the head node is null). The double linked list is different from the single linked list. We don't need to find the tail node every time. The double linked list itself has a tail node last. We just need to find this last and insert the new node

//Tail interpolation
   public void addLast(int data){
       ListNode node = new ListNode(data);//Create a new node to store the data to be inserted
       if (this.head==null){//Judge whether the head node is empty. If the head node is empty, the linked list is empty
           //Head node null belongs to the first insertion. Directly point the head node and tail node to the insertion node
           this.head=node;
           this.last=node;
       }else{//If not the first time
           this.last.next=node;//The new node becomes the back drive of the original tail node to realize tail insertion
           node.prev=last;//Then the original tail node becomes the precursor of the newly inserted node
           this.last=node;//Finally, set the newly inserted node as the tail node
       }
   }

🍈 Find out whether the keyword key is included in the double linked list

The incoming keyword key as like as two peas is introduced, and the local variable cur is traversed by the list. Which node's value equals key, which shows that the key in the linked list is returned to true, otherwise it will return false, which is exactly the same as the single linked list.

//Find out whether the keyword is included and whether the key is in the single linked list
   public boolean contains(int key){
       ListNode cur = this.head;//The local variable cur is introduced to traverse the linked list
       while(cur != null){
           if(cur.val==key){//If the val of the current node is equal to the keyword
               return true;//Return true
           }
           cur = cur.next;//Otherwise, continue to traverse backward
       }
       return false;//After traversing Chengdu, no key value is found, and false is returned
   }

🍈 Get the length of the double linked list

As like as two peas, cur is used to traverse the linked list, and more local variables size is set to count. As long as the node is not null, size is +1, and the last value to return size is the length of the linked list (in fact, the same is the same as the single linked list).

//Get the length of the double linked list
   public int size() {
       int size=0;//Set a count variable for counting
       ListNode cur = this.head;//Using cur instead of head node to traverse the linked list
       while (cur != null){//Traverse the linked list, and the node is not empty
           size++;//Counter + 1
           cur = cur.next;//Take a step back
       }
       return size;//After traversing the linked list, the value of the counter returned is the length of the linked list
   }

🍈 Insert at any position, and the first data node is subscript 0

Insertion principle: the temporary variable cur replaces the head node. Cur first goes to the position to be inserted, and then inserts the new node between cur and the previous node of cur, replacing the original position of cur to insert the node according to the position

//Insert at any position, and the first data node is subscript 0
   public void addIndex(int index,int data){
       ListNode node = new ListNode(data);//Create a new node to store the data to be inserted
       ListNode cur = this.head;//The temporary variable cur traverses the linked list instead of the head node
       if (index > 0 && index <size()) {//The insertion position is neither head nor tail
           for (int i = 0; i < index; i++){//Let cur go to the position to be inserted first
               cur = cur.next;
           }
           cur.prev.next=node;//Point the back drive of the previous node at the insertion position to the new node
           node.prev=cur.prev;//Point the precursor of the new node to the previous node at the insertion location, cur.prev
           node.next=cur;//By pointing the rear drive of the new node to the current cur, the insertion is realized. It is inserted between the cur and the previous node of cur, replacing the original position of cur
       }
       if (index ==size()){//The insertion position is at the tail
           addLast(data);//Direct tail interpolation
       }
       if (index==0){//The insertion position is at the head
           addFirst(data);//Direct head insertion
      }
       display();//Print the added linked list
   }

🍈 Delete the node whose keyword is key for the first time

First, judge whether the head node is null (whether the linked list is empty), and then find the node to be deleted. There are three kinds of nodes to be deleted
① Keyword in header node: set the next node of the header node as a new header node
② Keyword in tail node: set the last node on the tail node as a new tail node
③ If the keyword is not in the head node, the driver of the previous node of the key node points to the next node of the key node, and the driver of the next node of the key node points to the previous node of the key node

//Delete the node whose keyword is key for the first time
   public void remove(int key){
       ListNode cur = this.head;//Set cur to traverse the linked list instead of the head node
       while(cur != null){
           if(cur.val==key){//If the point to be deleted is found, there are three cases:
               if(cur==head){//In the head
                   head=head.next;//Set the next node of the node to be deleted as the new head node
                   if (head==null) {//If the double linked list has only one element, check it
                       break;
                   }
                   head.prev=null;//If there is more than one element, the precursor point of the head node is set to null
                   break;
               }
               if (cur==last){//In the tail
                   last=last.prev;//Set the previous node of the node to be deleted as the new tail node
                   last.next=null;//Empty the rear drive of the new tail node
                   break;
               } >               if (cur.prev!=null && cur.next!=null){//In the middle
                   cur.prev.next=cur.next;//Point the driver of the previous node of the key node to the next node of the key node
                   cur.next.prev=cur.prev;//Point the precursor of the next node after the key node to the previous node of the key node
                   break;
               }
           }
           cur=cur.next;//If you don't find the target point, take a step back
       }
       display();//Print the deleted double linked list
   }

🍈 Delete all nodes with the value of key

It is similar to deleting the key for the first time (Note: delete the key for the first time above), but do not break after deleting the node and let the traversal cycle continue

//Delete all nodes with the value of key
   public void removeAllKey(int key){
       ListNode cur = this.head;
       while(cur != null){
           if(cur.val==key){
               if(cur==head){//In the head
                   head=head.next;
                   if (head==null) {//There is only one element to check
                       break;
                   }
                   head.prev=null;
               }
               if (cur==last){//In the tail
                   last=last.prev;
                   last.next=null;
               }
               if (cur.prev!=null && cur.next!=null){//In the middle
                   cur.prev.next=cur.next;
                   cur.next.prev=cur.prev;
               }
           }
           cur=cur.next;
       }
       display();
   }

🍈 Empty linked list

Violent emptying, directly empty the head and tail nodes, so that the whole linked list can not be found

//Empty linked list
   public void clear() {
       head=null;
       last=null;
   }

🍉 What's the difference between a single linked list and a double linked list

1, Different references
1. Bidirectional linked list: also known as double linked list, it is a kind of linked list. There are two pointers in each data node, pointing to the direct successor and direct precursor respectively
2. Unidirectional linked list: it is a kind of linked list. Its feature is that the link direction of the linked list is unidirectional. Access to the linked list should start from the head through sequential reading.
2, Different advantages
1. Bidirectional linked list: starting from any node in the bidirectional linked list, you can easily access the precursor node and successor node.
2. Unidirectional linked list: it is very convenient to create a single node. Ordinary linear memory usually needs to set the size of data when creating. The access of nodes is convenient. Any data can be accessed through circular or recursive methods.
3, Different disadvantages
1. Two way linked list: adding and deleting nodes is complex, and one more pointer storage space needs to be allocated.
2. Unidirectional linked list: node deletion is very convenient. It does not need to move the remaining data like a linear structure, but the average access efficiency is lower than that of a linear list.

🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙
        ❤ Originality is not easy. If there is any error, please leave a message in the comment area. Thank you very much ❤
        ❤                 If you think the content is good, it's not too much to give a three company~        ❤
        ❤                              I'll pay a return visit when I see it~                                      ❤
🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙

Tags: Java data structure linked list

Posted on Fri, 12 Nov 2021 19:05:33 -0500 by mouloud2001