[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~ ❤

🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙🌙