What is a bidirectional list
A DoublyLinkedList: Also known as a double-linked list, is a type of linked list in which each data node has two Pointers to the next node and the previous node.
Unidirectional and bidirectional lists:
One-way linked list:
- You can only go from the beginning to the end or from the end to the end.
- The connection of nodes is one-way, the principle is that the previous node has a reference to the next node.
- It is easy to get to the next node, but difficult to return to the last node.
Bidirectional linked list:
- You can go from the beginning to the end or you can go from the end to the end.
- The process of node connection is bidirectional. The principle is that this node has a reference to the next node and a reference to the previous node.
Disadvantages of double-linked lists:
- It is cumbersome to operate on four references each time a node is added or removed.
- It takes up more memory than a one-way list
Double linked list structure:
- A bidirectional list has not only a head node to hold references to the first node, but also a tail node to hold references to the last node.
- Each node consists of three parts: data: stores data, next: stores references to the next node, and previous: stores references to the previous node.
- The previous node of the bidirectional list points to NULL, and the next node at the end points to NULL.
The bidirectional linked list is shown below:
The common method of bidirectional linked lists
- Append (data) adds a node to the tail
- Insert (position, data) Specifies the position to insert data
- GetData (position) Gets the list node at the specified position
- IndexOf (data) Finds the index of the data
- RemoveAt (position) Deletes the node at the specified position
- Update (position, data) Modifies the node at the specified position
- Remove (data) Removes the node where the specified data resides (inheriting one-way linked lists)
- IsEmpty () checks whether the list isEmpty
- Size () gets the length of the list
- ForwardToString () list data is returned as a string from front to back
- BackwardString () list data is returned as a string from back to front
ES6 implements a bidirectional linked list structure
- Bidirectional linked list internal node class encapsulation
/ * ** node class* data Indicates the data of the node* next stores a reference to the next node* Previous Holds a reference to the previous node * @class Node * /class Node { data; next = null; previous = null; constructor(data) { this.data = data; } } Copy the code
- Bidirectional linked list class encapsulation
class DoublyLinkedList {
length = 0;
// Store a reference to the header head = null;
// Store a reference to the end node tail = null; } Copy the code
- Append (data) method implementation
// append(data) adds a node to the tail append(data) {
// 1. Create new list nodes const newNode = new Node(data);
// Appends elements if (this.length === 0) { // If the list is empty this.head = newNode; this.tail = newNode; } else { // Append to the end of the list// The neat thing is that instead of looping around to find the end of the list, there is now a reference to the end node in tail this.tail.next = newNode; newNode.previous = this.tail; this.tail = newNode; } // The length increases this.length++; } Copy the code
- Insert (position, data) method implementation
// insert(position, data) Specifies the position to insert data insert(position, data) {
// Determine if the boundary is crossed if (position < 0 || position > this.length) return false;
// Create a new list node const newNode = new Node(data); // Append the list node; Here are some common cases:// 1. The empty list is appended to the header// 2. The linked list has data appended to the header// 3. Append to tail// 4. 0---- append this. Length if (position === 0) { // Append to the header if (this.head === null) { // No data is added to the head of the list this.head = newNode; this.tail = newNode; } else { // The linked list has data added to the header newNode.next = this.head; this.head.previous = newNode; this.head = newNode; } } else if (position === this.length) { // Insert nodes at the end of the list this.tail.next = newNode; newNode.previous = this.tail; this.tail = newNode; } else { // 0 -- this.length is inserted in the middle // Prepare variables lettargetIndex = 0; // The index representing the location of the node let currentNode = this.head; letpreviousNode = null; // represents the previous node // loop to find the node while (targetIndex++ < position) { previousNode = currentNode; currentNode = currentNode.next; } / / insert previousNode.next = newNode; newNode.previous = previousNode; newNode.next = currentNode; currentNode.previous = newNode; } // Increase the length this.length++; return true; } Copy the code
- GetData (position) method implementation
// getData(position) gets the list node at the specified position getData(position = 0) {
// Judge out of bounds if (position < 0 || position >= this.length) return false;
// loop to find the location lettargetIndex = 0; // The index representing the location of the node let currentNode = this.head; while (targetIndex++ < position) { currentNode = currentNode.next; } / / return return currentNode.data; } Copy the code
- IndexOf (data) method implementation
// indexOf(data) Finds the index corresponding to the data indexOf(data) {
// loop to find data
let targetIndex = 0;
let currentNode = this.head; while (currentNode) { if (data === currentNode.data) { return targetIndex; } currentNode = currentNode.next; targetIndex++; } // Otherwise return -1 return- 1; } Copy the code
- RemoveAt (Position) method implementation
// removeAt(position) Deletes the node at the specified position removeAt(position) {
// Determine if the boundary is crossed if (position < 0 || position >= this.length) return false;
let currentNode = this.head;
// Delete according to different circumstances if (position === 0) { // 1. Delete the header if (this.length === 1) { // If the list has only one node this.head = null; this.tail = null; } else { // If the list has more than one node this.head = this.head.next; this.head.previous = null; } } else if (position === this.length) { // Delete the last node of the list this.tail.previous.next = null; this.tail = this.tail.previous; } else { // 0-----this.length let targetIndex = 0; let previousNode = null; // Cycle to find positions while (targetIndex++ < position) { previousNode = currentNode; currentNode = currentNode.next; } / / delete previousNode.next = currentNode.next; currentNode.next.previous = previousNode; } // Length decrement this.length--; return currentNode.data; } Copy the code
- Update (position, data) method implementation
// Update (position, data) Modifies the node at the specified position update(position, data) {
// Determine the boundary if (position < 0 || position >= this.length) return false;
// loop to find the location let targetIndex = 0; let currentNode = this.head; while (targetIndex++ < position) { currentNode = currentNode.next; } currentNode.data = data; return currentNode.data; } Copy the code
- Remove (data) method implementation
//remove(data) remove the node where the specified data resides.
remove(data) {
return this.removeAt(this.indexOf(data));
}
Copy the code
- An implementation of isEmpty()
// isEmpty() checks if the list isEmpty isEmpty() {
return this.length === 0;
}
Copy the code
- An implementation of the size() method
// size() gets the length of the list size() {
return this.length;
}
Copy the code
- Implementation of the forwardToString() method
// forwardToString() list data is returned as a string from front to back forwardToString() {
let currentNode = this.head;
let result = "";
// Iterate over all nodes, concatenating them into strings until the node is null while (currentNode) { result += currentNode.data + "--"; currentNode = currentNode.next; } return result; } Copy the code
- Implementation of the backwardString() method
// backwardString() list data is returned as a string from back to front backwardString() {
let currentNode = this.tail;
let result = "";
// Iterate over all nodes, concatenating them into strings until the node is null while (currentNode) { result += currentNode.data + "--"; currentNode = currentNode.previous; } return result; } Copy the code
Bidirectional linked list overall code
class Node {
data;
next = null;
previous = null;
constructor(data) {
this.data = data; } } class DoublyLinkedList { length = 0; // Store a reference to the header head = null; // Store a reference to the end node tail = null; // Two-way linked list method// append(data) adds a node to the tail append(data) { // 1. Create new list nodes const newNode = new Node(data); // Appends elements if (this.length === 0) { // If the list is empty this.head = newNode; this.tail = newNode; } else { // Append to the end of the list// The neat thing is that instead of looping around to find the end of the list, there is now a reference to the end node in tail this.tail.next = newNode; newNode.previous = this.tail; this.tail = newNode; } // The length increases this.length++; } // insert(position, data) Specifies the position to insert data insert(position, data) { // Determine if the boundary is crossed if (position < 0 || position > this.length) return false; // Create a new list node const newNode = new Node(data); // Append the list node; Here are some common cases:// 1. The empty list is appended to the header// 2. The linked list has data appended to the header// 3. Append to tail// 4. 0---- append this. Length if (position === 0) { // Append to the header if (this.head === null) { // No data is added to the head of the list this.head = newNode; this.tail = newNode; } else { // The linked list has data added to the header newNode.next = this.head; this.head.previous = newNode; this.head = newNode; } } else if (position === this.length) { // Insert nodes at the end of the list this.tail.next = newNode; newNode.previous = this.tail; this.tail = newNode; } else { // 0 -- this.length is inserted in the middle // Prepare variables lettargetIndex = 0; // The index representing the location of the node let currentNode = this.head; letpreviousNode = null; // represents the previous node // loop to find the node while (targetIndex++ < position) { previousNode = currentNode; currentNode = currentNode.next; } / / insert previousNode.next = newNode; newNode.previous = previousNode; newNode.next = currentNode; currentNode.previous = newNode; } // Increase the length this.length++; return true; } // getData(position) gets the list node at the specified position getData(position = 0) { // Judge out of bounds if (position < 0 || position >= this.length) return false; // loop to find the location lettargetIndex = 0; // The index representing the location of the node let currentNode = this.head; while (targetIndex++ < position) { currentNode = currentNode.next; } / / return return currentNode.data; } // indexOf(data) Finds the index corresponding to the data indexOf(data) { // loop to find data let targetIndex = 0; let currentNode = this.head; while (currentNode) { if (data === currentNode.data) { return targetIndex; } currentNode = currentNode.next; targetIndex++; } // Otherwise return -1 return- 1; } // removeAt(position) Deletes the node at the specified position removeAt(position) { // Determine if the boundary is crossed if (position < 0 || position >= this.length) return false; let currentNode = this.head; // Delete according to different circumstances if (position === 0) { // 1. Delete the header if (this.length === 1) { // If the list has only one node this.head = null; this.tail = null; } else { // If the list has more than one node this.head = this.head.next; this.head.previous = null; } } else if (position === this.length) { // Delete the last node of the list this.tail.previous.next = null; this.tail = this.tail.previous; } else { // 0-----this.length let targetIndex = 0; let previousNode = null; // Cycle to find positions while (targetIndex++ < position) { previousNode = currentNode; currentNode = currentNode.next; } / / delete previousNode.next = currentNode.next; currentNode.next.previous = previousNode; } // Length decrement this.length--; return currentNode.data; } // Update (position, data) Modifies the node at the specified position update(position, data) { // Determine the boundary if (position < 0 || position >= this.length) return false; // loop to find the location let targetIndex = 0; let currentNode = this.head; while (targetIndex++ < position) { currentNode = currentNode.next; } currentNode.data = data; return currentNode.data; } //remove(data) remove the node where the specified data resides. remove(data) { return this.removeAt(this.indexOf(data)); } // isEmpty() checks if the list isEmpty isEmpty() { return this.length === 0; } // size() gets the length of the list size() { return this.length; } // forwardToString() list data is returned as a string from front to back forwardToString() { let currentNode = this.head; let result = ""; // Iterate over all nodes, concatenating them into strings until the node is null while (currentNode) { result += currentNode.data + "--"; currentNode = currentNode.next; } return result; } // backwardString() list data is returned as a string from back to front backwardString() { let currentNode = this.tail; let result = ""; // Iterate over all nodes, concatenating them into strings until the node is null while (currentNode) { result += currentNode.data + "--"; currentNode = currentNode.previous; } return result; } } Copy the code