[preface] in the previous article, we have learned about the basic functions of sequential list and single linked list. Next, let's learn how to realize the basic functions of two-way linked list. First, let's take a look at the structure of the two-way linked list:
Headless bidirectional linked list
Concept and structure of bidirectional linked list
Concept: bidirectional linked list, also known as double linked list, is a kind of linked list. There are two pointers in each data node, pointing to the direct successor and direct precursor respectively. Therefore, starting from any node in the two-way linked list, you can easily access its predecessor node and successor node.
Structure:
Implementation of linked list
Before we implement the interface function of the linked list, we need to create two classes, the linked list class (including a variable head node and variable tail node and interfaces to realize various functions) and the node class (including the member attribute value, prev precursor and next successor).
class ListNode{ public int value;//Data domain public ListNode prev;//precursor public ListNode next;//Successor public ListNode(int value){ this.value= value; } }
public class LinkList { public ListNode head;//Defines the header reference of the linked list public ListNode last;//Defines the tail node of the linked list }
Print double linked list
Its idea is similar to the idea of printing sequence table. You can traverse the linked list, but it should be noted that you need to create a local variable cur to traverse instead of the head node, because the head node is fixed before adding or deleting nodes, and you can't let it change.
public void disply(){ ListNode cur=this.head;//Reference the variable cur instead of the header node while(cur!=null){//When the node is not empty, traverse the single linked list. If the node is empty, the traversal ends System.out.print(cur.value+" "); cur=cur.next;//Point to next node } System.out.println(); }
Gets the length of the double linked list
Reference the local variable cur to traverse the linked list, and reference a local variable count to count. As long as the node is not null, the count will be + 1, and the last returned count value is the length of the linked list. (consistent with the single linked list method)
public int size(){ ListNode cur=this.head; int count=0 ;//The local variable count is introduced to count while(cur!=null){ count++;//Counter + 1 when cur is not empty cur=cur.next;//cur goes back and points to the next node } return count;//Return double linked list length }
Find out whether the keyword is included and whether the key is in the double linked list
Pass in the keyword key and introduce the local variable cur to traverse the linked list. If the same element as the key is encountered during the traversal, it returns true, otherwise it returns false. (consistent with the single linked list method)
public boolean contains(int key){ ListNode cur=this.head;//The local variable cur is introduced to traverse the linked list instead of the head node while(cur!=null){ if(cur.value==key)//When equal, it indicates that the linked list contains the keyword key and returns true return true; cur=cur.next;//Traverse the next node } //When the variable cur is empty, the traversal ends and the loop jumps out. The linked list does not contain this keyword and returns false return false; }
Head insertion
The so-called head insertion method is to insert a node in front of the head node. First, we need to judge whether the head node is empty. If it is empty, the new node created will be the head node and tail node directly; If it is not empty, the successor of the newly inserted node points to the original head node, the precursor of the original head node points to the newly inserted node, and finally set the newly inserted node as the head node.
public void addFirst(int data){ ListNode node=new ListNode(data);//Create a new node and store the data to be inserted if(this.head==null){//Judge whether the header node is empty. If the header node is empty, it indicates that it is the first insertion this.head=node;//Directly point the head node and tail node to the insertion node this.last=node; } else{//If not for the first time node.next=this.head;//The successor of the newly inserted node points to the head node this.head.prev=node;//Point the precursor of the original head node to the newly inserted node this.head=node;//Finally, set the newly inserted node as the head node } }
Tail interpolation
The tail insertion method is similar to the head insertion method. You must first judge whether the head node is empty. If it is empty, it indicates that it is the first insertion. You can directly point the head node and tail node to the newly inserted node. If it is not empty, find the last node of the double linked list, and then insert the new node.
public void addLast(int data){ ListNode node=new ListNode(data);//Create a new node and store the data to be inserted if(this.head==null){//Judge whether the header node is empty. If the header node is empty, it indicates that it is the first insertion this.head=node;//Directly point the head node and tail node to the insertion node this.last=node; } else{//If not for the first time this.last.next=node;//Point the successor of the original tail node to the newly inserted node node.prev=this.last;//The precursor of the new node is the original tail node this.last=node;//Finally, the newly inserted node becomes the tail node } }
Insert at any position, and the first data node is subscript 0
First, we need to judge whether the insertion position is reasonable. Then, if we want to insert a node at any position, we must first find the insertion position, and then insert the newly created node between the current node and the previous node. Because it is a double linked list, we should pay attention to the changes of the precursor and subsequent nodes.
//Find insertion location public ListNode searchIndex(int index){ ListNode cur=this.head;//The local variable count is introduced to count while(index!=0){//Traverse the linked list to find the location to insert cur=cur.next;//cur goes back and points to the next node index--;//Subscript-1 } return cur; } //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 and store the data to be inserted //Determine whether the insertion position is legal if(index<0||index>size()){ System.out.println("Illegal insertion position"); return; } //If the insertion position is 0, it is header insertion. You can call header insertion directly if(index==0){ addFirst(data); return ; } //If the insertion position is the position of the length of the linked list, it is tail insertion. You can directly call the tail insertion method if(index==size()){ addLast(data); return; } ListNode cur=searchIndex(index);//Reference the variable cur to receive the insertion location returned by the searchIndex method node.next=cur.prev.next;//Make the successor of the newly inserted node point to the successor node of the predecessor of the insertion position cur.prev.next=node;//The successor node of the predecessor node at the insertion position is the newly inserted node node.prev=cur.prev;//The precursor node of the newly inserted node becomes the precursor node at the insertion position cur.prev=node;//The precursor node at the inserted position becomes the newly inserted node }
Delete the node whose keyword is key for the first time
First, we need to judge whether the linked list is empty (that is, whether the head node is empty). Second, we need to see whether the key node to be deleted is the head node. If it is the head node, we will directly point the reference of the head node to the next node, and the next node will become the head node; If the keyword is in the tail node, set the previous node of the tail node as the new tail node; If the keyword is an intermediate node, the successor of the previous node of the key node points to the next node of the key node, and the predecessor of the next node of the key node points to the previous node of the key node.
public void remove(int key){ ListNode cur=this.head;//Reference the variable cur instead of the header node while(cur!=null){//Traverse the linked list if(cur.value==key){//If the value of the node is equal to the keyword key, enter the loop if(cur==this.head){//If the header node is the keyword key this.head=this.head.next;//The head node points directly to the next node if(this.head!=null) {//If there is only one element in the linked list, check it this.head.prev = null;//Otherwise, null pointer exception will occur } else{ this.last=null; } } else{//If the keyword is at the end or in the middle cur.prev.next=cur.next;//Make the successor of the previous node of the current node point to the next node of the current node if(cur==this.last){//Keyword key at the end last=last.prev;//The previous node of the tail node is the last node }else{ //Intermediate node cur.next.prev=cur.prev;//The predecessor of the next node after the current node points to the previous node of the current node } /* if(this.last.next!=null){ cur.next.prev=cur.prev; } last=last.prev; */ } return ;//Interrupt when keyword key is found } cur=cur.next;//If not found, cur continues to point to the next node } }
Delete all nodes with the value of key
It is similar to the above method of deleting a node with the keyword key for the first time, except that the above method does not go down after finding a node with the keyword key. This method of deleting all nodes with the value key is to continue to go down after finding the first key until all the nodes are found.
public void remove(int key){ ListNode cur=this.head;//Reference the variable cur instead of the header node while(cur!=null){//Traverse the linked list if(cur.value==key){//If the value of the node is equal to the keyword key, enter the loop if(cur==this.head){//If the header node is the keyword key this.head=this.head.next;//The head node points directly to the next node if(this.head!=null) {//If there is only one element in the linked list, check it this.head.prev = null;//Otherwise, null pointer exception will occur } else{ this.last=null; } } else{//If the keyword is at the end or in the middle cur.prev.next=cur.next;//Make the successor of the previous node of the current node point to the next node of the current node if(cur==this.last){//Keyword key at the end last=last.prev;//The previous node of the tail node is the last node }else{ //Intermediate node cur.next.prev=cur.prev;//The predecessor of the next node after the current node points to the previous node of the current node } /* if(this.last.next!=null){ cur.next.prev=cur.prev; } last=last.prev; */ } } cur=cur.next;//If not found, cur continues to point to the next node } }
Empty linked list
It is similar to the method of empty single linked list, except that there are more precursors of empty nodes, and the tail node should also be empty.
public void clear(){ //When the header node is not empty while(this.head!=null){ ListNode curNext=this.head.next;//Reference the variable curNext to save the next node of the header node this.head.next=null;//Set the next in the header node to null this.head.prev=null;//Set the prev in the header node to null this.head=curNext;//Set the next node as the head node } this.last=null;//The tail node should also be empty }