Unlike a single linked list, each node of a bidirectional linked list contains not only data, but also Pointers to its front and back nodes
In fact, compared with a single linked list, a double-linked list is a new pointer to the previous node
Let me write a double-linked list by hand to achieve some methods:
Let’s start by implementing a node constructor:
class Node {
constructor(element) {
this.element = element; // Node data value
this.next = null; / / before the pointer
this.prev = null; / / after the pointer}}Copy the code
Bidirectional linked list overall structure
class DoubleLinkedList {
constructor() {
this.count = 0; // Record the number of nodes
this.head = null; // Two-way list header
this.tail = null; // The end of the bidirectional list
}
// Add nodes to the end of the list
add(element) {}
// add a node to the list at the specified location
addAt(index, element) {}
// Remove the node at the specified position in the list
removeAt(index) {}
// Remove the specified node from the list
remove(element) {}
// Flip the linked list
reverse() {}
// Switch the position of two nodes
swap() {}
// Iterate over the list
traverse() {}
// Find the index of a node
find() {}
// Check whether the linked list is empty
isEmpty() {}
// Query the length of the list
length(){}}Copy the code
The next step is to implement each of these methods
The node is found by location (index), and the method that follows will be used all the time, simply wrapping it up as a method to call
getElement(index) {
if (index >= 0 && index < this.count) {
let node = this.head;
// Loop through the node
for (let i = 0; i < index; i++) {
node = node.next;
}
return node;
}
return undefined;
}
Copy the code
1. Add a node
1.1 Adding nodes at the end
// Pass in a node
add(element) {
// Create a node
const node = new Node(element);
// If the list is empty, then both the head node and the tail node are nodes
if (this.head === null && this.tail === null) {
this.head = node;
this.tail = node
}
// If the list already has a header, add a node to the end
else {
node.prev = this.tail;
this.tail.next = node;
this.tail = node;
}
// Total number of nodes +1
this.count++;
}
Copy the code
1.2 Add a node at the specified location in the linked list
addAt(index, element) {
if (index >= 0 && index <= this.count) {
const node = new Node(element);
// When inserted in the header
if (index === 0) {
this.head.prev = node;
node.next = this.head;
this.head = node;
}
// Insert nodes at the end
else if (index === this.count) {
this.add(element)
this.count--;
}
// Insert nodes in the middle
else {
let current = this.getElement(index);
// Set the relationship between the new node and the previous node
node.prev = current.prev;
current.prev.next = node;
// Add the relationship to the next node
node.next = current;
current.prev = node
}
this.count++;
return true
}
return false;
}
Copy the code
2. Remove the node
2.1. Remove the node at the specified position in the linked list
removeAt(index) {
if (index >= 0 && index < this.count) {
// Remove the head node
if (index === 0) {
this.head = this.head.next;
this.head.prev = null;
}
// Remove the tail node
else if (index === this.count - 1) {
this.tail = this.tail.prev;
this.tail.next = null;
}
// Remove the intermediate node
else {
let current = this.getElement(index);
current.next.prev = current.prev
current.prev.next = current.next
}
this.count--;
return true
}
return undefined;
}
Copy the code
2.2. Remove the specified node in the linked list
To remove a specified node, the first step is to find the node
remove(element) {
let current = this.head;
while (current) {
if (current === element) {
// The list has only one node
if (current === this.head && current === this.prev) {
this.head = null;
this.tail = null;
}
// Remove the head node
else if (current === this.head) {
this.head = this.head.next;
this.head.prev = null;
}
// Remove the tail node
else if (current === this.tail) {
this.tail = this.tail.prev;
this.tail.next = null;
}
// Remove the intermediate node
else {
current.next.prev = current.prev;
current.prev.next = current.next;
}
this.count--; } current = current.next; }}Copy the code
5. Flip the list
reverse() {
let current = this.head;
let prev = null;
// Put the middle one first
while (current) {
let next = current.next;
// back to front
current.next = prev;
current.prev = next;
prev = current;
current = next
}
this.tail = this.head;
this.head = prev
}
Copy the code
6. Switch the two nodes
swap(index1, index2) {
if (index1 >= 0 && index1 < this.count && index2 >= 0 && index2 < this.count) {
let node1 = this.getElement(index1)
let node2 = this.getElement(index2)
// let index1 always be less than index2 for easy lookup swaps
if (index1 > index2) {
return this.swap(index2, index1)
}
// Swap the values of the two nodes
[node1.element, node2.element] = [node2.element, node1.element]
return true
}
return undefined;
}
Copy the code
Iterate over the linked list
display() {
if (!this.isEmpty()) {
let current = this.head;
let result = ' ';
while (current) {
result += current.element
current = current.next
if (current) {
result += '- >'; }}return result;
}
return undefined;
}
Copy the code
8. Find the index of a node
find(element) {
let current = this.head;
let index = 0
while (current) {
if (current === element) {
return index;
}
current = current.next;
index++;
}
return undefined
}
Copy the code
Check whether the linked list is empty
isEmpty() {
return this.count === 0
}
Copy the code
Query the length of the list
length() {
return this.count;
}
Copy the code
Put it all together:
// Implement a node constructor
class Node {
constructor(element) {
this.element = element;
this.next = null;
this.prev = null; }}// Two-way linked list
class DoubleLinkedList {
constructor() {
this.count = 0; // Record the number of nodes
this.head = null; // Two-way list header
this.tail = null; // The end of the bidirectional list
}
// Loop through a method to the destination
getElement(index) {
if (index >= 0 && index < this.count) {
let node = this.head;
for (let i = 0; i < index; i++) {
node = node.next;
}
return node;
}
return undefined;
}
// Add nodes to the end of the list
add(element) {
// Create a node
const node = new Node(element);
// If the list is empty
if (this.head === null && this.tail === null) {
this.head = node;
this.tail = node
}
// If the list already has a header, add a node to the end
else {
node.prev = this.tail;
this.tail.next = node;
this.tail = node;
}
this.count++;
}
// add a node to the list at the specified location
addAt(index, element) {
if (index >= 0 && index <= this.count) {
const node = new Node(element);
// When inserted in the header
if (index === 0) {
this.head.prev = node;
node.next = this.head;
this.head = node;
} else if (index === this.count) {
this.add(element)
this.count--;
}
// Non-head insertion
else {
let current = this.getElement(index);
// Set the relationship between the new node and the previous node
node.prev = current.prev;
current.prev.next = node;
// Add the relationship to the next node
node.next = current;
current.prev = node
}
this.count++;
return true
}
return false;
}
// Remove the node at the specified position in the list
removeAt(index) {
if (index >= 0 && index < this.count) {
// Remove the head node
if (index === 0) {
this.head = this.head.next;
this.head.prev = null;
}
// Remove the tail node
else if (index === this.count - 1) {
this.tail = this.tail.prev;
this.tail.next = null;
}
// Remove the intermediate node
else {
let current = this.getElement(index);
current.next.prev = current.prev
current.prev.next = current.next
}
this.count--;
return true
}
return undefined;
}
// Remove the specified node from the list
remove(element) {
let current = this.head;
while (current) {
if (current === element) {
// The list has only one node
if (current === this.head && current === this.prev) {
this.head = null;
this.tail = null;
}
// Remove the head node
else if (current === this.head) {
this.head = this.head.next;
this.head.prev = null;
}
// Remove the tail node
else if (current === this.tail) {
this.tail = this.tail.prev;
this.tail.next = null;
}
// Remove the intermediate node
else {
current.next.prev = current.prev;
current.prev.next = current.next;
}
this.count--; } current = current.next; }}// Flip the linked list
reverse() {
let current = this.head;
let prev = null;
while (current) {
let next = current.next;
// back to front
current.next = prev;
current.prev = next;
prev = current;
current = next
}
this.tail = this.head;
this.head = prev
}
// Switch the position of two nodes
swap(index1, index2) {
if (index1 >= 0 && index1 < this.count && index2 >= 0 && index2 < this.count) {
let node1 = this.getElement(index1)
let node2 = this.getElement(index2)
// let index1 always be less than index2 for easy lookup swaps
if (index1 > index2) {
return this.swap(index2, index1)
}
// Swap the values of the two nodes
[node1.element, node2.element] = [node2.element, node1.element]
return true
}
return undefined;
}
// Iterate over the list
display() {
if (!this.isEmpty()) {
let current = this.head;
let result = ' ';
while (current) {
result += current.element
current = current.next
if (current) {
result += '- >'; }}return result;
}
return undefined;
}
// Find the index of a node
find(element) {
let current = this.head;
let index = 0
while (current) {
if (current === element) {
return index;
}
current = current.next;
index++;
}
return undefined
}
// Check whether the linked list is empty
isEmpty() {
return this.count === 0
}
// Query the length of the list
length() {
return this.count; }}Copy the code
Let’s call:
// Instantiate a bidirectional list object
let DLL = new DoubleLinkedList();
// add a tail
DLL.add(1);
DLL.add(2);
// Add it anywhere
DLL.addAt(0.3);
DLL.addAt(3.6);
/ / traverse
console.log(DLL.display()); / / 3 - > 1 - > 2 - > 6
// Delete by location
DLL.removeAt(3);
// Switch two nodes
DLL.swap(0.2)
console.log(DLL.display()); / / 1 - > 2 - > 3
/ / flip
DLL.reverse();
// Whether the linked list is empty
console.log(DLL.isEmpty()); // false
// List length
console.log(DLL.length()); / / 3
Copy the code
Conclusion:
- So you can see that implementing a linked list is nothing more than adding (adding nodes) deleting (deleting nodes) changing (swapping) looking up (traversing)
- Adding and removing nodes is nothing more than changing the pointer to the node