JS implement double linked list
Before: humble just want to grasp the knowledge points, recorded, but convenient query and review their knowledge points, if there is anything wrong, I hope to be able to point out the mistakes.
There have been two or three months did not write digging blog, the front also wrote a little knowledge about data structure, also very fur, today to share the next linked list in the double linked list, the front also shared very rough single linked list knowledge points, can be quickly viewed.
** double linked list: ** is a kind of linked list, is a kind of pointer before and after, respectively pointing to the precursor node and the successor node, mainly to solve the problem of the previous node, in practical use, when we actually want to use the data of the last node, for the single linked list, is the need to iterate.
The structure of doubly linked lists
Double linked list implementation
This paper will implement several main methods of double linked list, respectively:
-
Append is added to the tail
-
IndexOf returns the position of an element
-
IndexEle returns the element at a location
-
Insert Inserts a position
-
RemoveAt Removes a location
-
RemoveEle removes an element
-
Remove Removes the last element
-
GetSize returns the length of the double-linked list
-
IsEmpty returns whether the doubly linked list isEmpty
-
GetHead returns the head of the double-linked list
-
GetTail returns the end of the double-linked list
-
String Returns a string.
-
GetCurrentAndPrev returns [current element, prev node]
defineNode
node
class Node {
constructor(element) {
this.element = element;
this.next = null;
this.prev = null; // Add a pre pointer to the list to keep track of the previous node.}}Copy the code
Define double-linked lists
- Because we need to record
head
andtail
Nodes, so we need to add more than a single linked listtail
Node to record the last node.
class DoubleLinked {
constructor() {
this.head = null;
this.tail = null;
this.count = 0; }}Copy the code
append
Add a tail element
- Judgment condition: If
head
为null
, you need to set the value of the newly added node tohead
- if
head
Don’t fornull
, you need to traverse to the last elementcurrent
That will benext
Assignment, we need to modify itprev
Pointer tocurrent
- Each new addition needs to be added
count+1
append(element) {
const node = new Node(element);
let current = this.head;
if(! current) {this.head = node;
this.tail = node;
} else {
while (current.next) {
current = current.next
}
current.next = node;
node.prev = current;
this.tail = node; // You can also use this.tail.next = node;
}
this.count++;
}
Copy the code
insert
: Inserts elements to a location
- Judge, consider the transgression situation
- when
position = 0
You need to determinethis.head
Presence or absence of - when
position > 0 && position < this.count
Find the last valuepreNode
, point the tail pointer tonode
.node
theprev
Point to thepreNode
.node
The tail pointer points tonextNode
.nextNode
theprev
Pointer tonode
.count+1
- when
position = this.count
, can be directly usedappend
Method,tail
Points to the additionnode
position > this.count
; returnfalse
Params {* element: the element to be inserted * position: the position to be inserted *} * Judge * 1. * position > 0 && position < this.count Find the last value preNode and point the tail pointer to node. The prev of a node points to a preNode, the tail of a node points to a nextNode, Append * position > this.count; Returns false * /
insert(element, position) {
let current = this.head;
const node = new Node(element);
let previous = null;
// position is 0, we need to consider whether head is null
if(position === 0) {
// If head is null
if(! current) {this.head = node // Assign head directly to node
this.tail = node // Also assign tail to node
}else {
node.next = current; // node replaces current with next pointer to current
current.prev = node;
this.head = node;
// We don't use this.tail here because we're just replacing head, tail still refers to the last element;
}
this.count++;
}else if (position > 0 && position <= this.count){
// Find the element in position
let index = 0
while(index < position) {
previous = current;
current = current.next;
index++;
}
// If length is the last element, current is null and node is the last element
if(index ! = =this.count) {
node.next = current;
current.prev = node;
}else {
this.tail = node;
}
previous.next = node
node.prev = previous;
this.count++;
}else {
return false}}Copy the code
indexOf
: Finds the index of the current element
- The judgment considers the boundary problem and returns if beyond is not found
- 1
- Traverse to find, find returns
index
Index, here is the default to find the first element, the following elements are not considered
// Find the element in the current position
indexOf(element) {
// Check current = current. Next
let index = 0;
let current = this.head;
while(current && index < this.count){
if(current.element === element) {
return index
}
current = current.next;
index++;
}
return -1;
}
Copy the code
indexEle
: Finds the element in the current position
- The judgment considers the boundary problem and returns if beyond is not found
false
, returns the current element if found
indexEle(position) {
let ele = null;
if(position >= 0 && position < this.count){
let current = this.head;
while(position > 0) {
current = current.next;
position--;
}
ele = current;
}
return ele
}
Copy the code
removeAt
: Delete the element
- Judge and consider the boundary overflow problem.
- when
position===0 && head
, you need to changehead
The assignment forele.next
And at the same time willele.prev
Set tonull
- when
position > 0 && head && postion < count - 1
When willprevious.next = current.next; current.next.prev = previous
- when
position === count - 1
, you only need to changeprevious.next = null; this.tail = previous;
- In other cases,
! head || position > count-1
Both returnfasle
/** * removeAt removes the element ** /
removeAt(position) {
// Find the element in the current position
let ele = this.indexEle(position);
// We have already judged the transgression situation.
if(ele) {
// Set the prev pointer to null when poistion === 0 is considered
if(position === 0) {
this.head = ele.next;
ele.prev = null;
}else {
// Find the previous pointer element
let previous = this.indexEle(position - 1);
// In the same case, next=null should be considered for the boundary case
if(position === this.count - 1) {
previous.next = null;
this.tail = previous;
// console.log({'tail': this.tail})
}else {
previous.next = ele.next;
ele.next.prev = previous
}
}
// Quantity minus one
this.count--;
return true
}
return false
}
Copy the code
removeEle
: Delete element
- Consider element duplication, where all elements that are equal need to be deleted
/** * removeEle removes elements */
removeEle(element){
let current = this.head;
let previous = null;
let num = 0
if(current.element === element) {
// We need to remove the first element, because the next element is from current. Next, so we can't delete the element if the head has ele
this.head = current.next;
current.next.prev = null;
this.count--;
num++
}
previous = current;
current = current.next;
while(current) {
if(current.element === element) {
previous.next = current.next;
// If it is not a tail pointer, it is necessary to execute a forepointer pointer
if(current.next){
current.next.prev = previous;
}else {
this.tail = previous
}
this.count--; / / the length - 1
num++
}else {
previous = current;
}
current = current.next;
}
return num === 0 ? -1 : num;
}
Copy the code
remove
Delete the last element
remove() {
let current = this.head;
// Head is null when deleted
if(this.count === 0) {
return false
}else if (this.count === 1) { // Delete only head
this.head = null;
this.tail = null;
this.count--;
return current.element
}else {
// To delete the last one, reassign tail to previous
let previous = null
while(current.next) {
previous = current;
current = current.next;
}
previous.next = null;
this.tail = previous;
this.count--;
returncurrent.element; }}Copy the code
stirng
: Converts to a string
string() {
let str = ' ';
let current = this.head;
while (current) {
str += current.element;
current = current.next;
}
return str;
}
Copy the code
getHead
: Gets the head node
getHead() {
return this.head && this.head.element || null;
}
Copy the code
getTail
: Gets the last node
getTail() {
return this.tail && this.tail.element || null;
}
Copy the code
getSize
: Gets the length
getSize() {
return this.count;
}
Copy the code
isEmpty
: Checks whether the device is empty
isEmpty() {
return this.length === 0;
}
Copy the code
getCurrentAndPrev
: Gets the current element and the last node
getCurrentAndPrev() {
const arr = [];
let current = this.head;
while (current) {
arr.push([current.element, current.prev])
current = current.next;
};
return arr
}
Copy the code
The test data
const doubleLinked = new DoubleLinked()
// console.log(doubleLinked.string());
doubleLinked.append(2);
// console.log({'head1': doubleLinked.getHead()})
// console.log({'tail1': doubleLinked.getTail()})
doubleLinked.append(3);
console.log(doubleLinked.remove())
console.log(doubleLinked.remove())
// console.log({'head2': doubleLinked.getHead()})
// console.log({'tail2': doubleLinked.getTail()})
return;
doubleLinked.append(4);
doubleLinked.append('A');
doubleLinked.append('C');
doubleLinked.append('A');
// console.log({'head3': doubleLinked.getHead()})
// console.log({'tail3': doubleLinked.getTail()})
doubleLinked.insert('A'.0)
// console.log(doubleLinked.getSize())
doubleLinked.insert('B'.4)
doubleLinked.insert('C'.3)
console.log(doubleLinked.string());
// doubleLinked.removeAt(5)
// console.log(doubleLinked.indexEle(3))
// console.log(doubleLinked.indexOf('C'))
// console.log(doubleLinked.insert('D', 10)) // false
// console.log({'tail3': doubleLinked.getTail()})
console.log(doubleLinked.removeEle('A'))
console.log({'tail3': doubleLinked.getTail()})
console.log(doubleLinked.getSize())
console.log(doubleLinked.string());
console.log(doubleLinked.getCurrentAndPrev())
Copy the code