A list of multiple elements
The elements are stored discontiguously, connected by the next pointer
There are no linked lists in JavaScript
You can use Object to simulate linked lists
Arrays VS linked lists
Array: Moves elements when adding or deleting non-primacy elements
Linked list: When adding or deleting non-first elements, you don’t need to move the elements, just change the direction of next
Definition 1.
Stores an ordered collection of elements
It’s not continuous
A node that stores the element itself + a reference to the next element
2. Specific operations
create
class Node { // Represents the item you want to add to the list
constructor(element, next) {
this.element = element;
this.next = next; // A pointer to the next element in the list}}class LinkedList {
constructor() {
this.count = 0;
this.head = undefined; // Save the reference}}Copy the code
methods
// Returns the element at a specific location
getElementAt(index) {
if (index >= 0 && index <= this.count) {
let node = this.head;
for (let i = 0; i < index && node ! =null; i++) {
node = node.next; // Loop node to the index element
}
return node;
}
throw new Error("out range");
}
// Returns the index of the element in the linked list. Returns -1 if the element is not in the list
indexOf(element) {
let current = this.head;
for (let i = 0; i < this.size() && current ! =null; i++) {
if (current.element === element) {
return i;
}
current = current.next;
}
return -1;
}
// Add a new element to the tail
push(element) {
let node = new Node(element);
if (this.head == null) { // If the list is empty, add it directly to the header
this.head = node;
} else {
let current = this.head;
while(current.next ! =null) { // Get the last item
current = current.next;
}
. / / when the current next = = undefined | | null, that is to list the tail
//** The next element of the last node in the list is always undefined or null**
current.next = node; // Assign its next element to the new element and create a link
}
this.count++;
}
// You can also use this method
/ /...
// else {
// **let current = this.getElementAt(this.count - 1); ** // Find node
// **current.next = node; 支那
/ /}
/ /...
// Insert a new element at a specific location
insert(element, index) {
if (index >= 0 && index <= this.count) { // Within the range
let node = new Node(element);
if (index === 0) { // Add it directly to the header
const current = this.head;
node.next = current;
this.head = node;
} else {
const pre = this.getElementAt(index - 1); // Get the position of the previous node
node.next = pre.next; // The newly created node is assigned the value pre-.next
pre.next = node; // point pre-.next to the newly created node
}
this.count++; / / length + 1
return true;
}
throw new Error("out range");
}
// Remove an element from a specific position
removeAt(index) {
if (index >= 0 && index < this.count) {
let current = this.head;
if (index === 0) { // Remove the first item
this.head = current.next; // You can also use head=head.next
} else {
for (let i = 0; i < index; i++) { // From the removed position, the element moves forward one bit
let pre = current;
current = current.next;
}
// The pre pointer points to the first bit of the element to be removed and the next pointer points to the next bit of the element to be removed
pre.next = current.next;
}
this.count--;
return current.element;
}
return undefined; // If index is not in the range, return undefined
}
// Remove an element
remove(element) {
const index = this.indexOf(element);
return this.removeAt(index);
}
isEmpty() {
return this.size() === 0;
}
size() {
return this.count;
}
getHead() {
return this.head;
}
clear() {
this.head = undefined;
this.count = 0;
}
// Convert the LinkedList object to a string
toString() {
if (this.head == null) {
return ' ';
}
let objString = `The ${this.head.element}`;
let current = this.head.next;
for (let i = 1; i < this.size() && current ! =null; i++) {
objString = `${objString}.${current.element}`;
current = current.next;
}
return objString;
}
Copy the code
3. Bidirectional linked lists
Links are bidirectional: one chain down the element, the other chain up the element
Advantage: In a one-way linked list, if you miss an element while iterating, you need to go back to the starting point and start iterating again
A bidirectional list controls both the next and prev Pointers
class Node {
constructor(element, next) {
this.element = element;
this.next = next; }}function defaultEquals(a, b) {
return a === b;
}
class LinkedList {
constructor(equalsFn = defaultEquals) {
this.count = 0;
this.head = undefined;
this.equalsFn = equalsFn; }}class DoublyNode extends Node {
constructor(element,next,prev) {
super(element,next);
this.prev = prev; }}class DoublyLinkedList extends LinkedList {
constructor(equalasFn = defaultEquals) {
super(equalasFn);
this.tail = undefined; }}Copy the code
insert(element, index) {
if (index >= 0 && index <= this.count) {
const node = new DoublyNode(element);
let current = this.head;
if (index === 0) {
if(this.head == null) { // This. Head and this.tail point directly to node
this.head = node;
this.tail = node;
} else {
node.next = this.head;
current.prev = node;
this.head = node; }}else if (index === this.count) { // Insert to the end
current = this.tail;
current.next = node;
node.prev = current;
this.tail = node;
} eles {
const previous = this.getElementAt(index - 1); // Find the position before the insertion point
current = previous.next;
node.next = current;
previous.next = node;
current.prev = node;
node.prev = previous;
}
this.count++;
return true;
}
return false;
}
removeAt(index) {
if (index >= 0 && index < this.count) { // Within the range
let current = this.head;
if (index === 0) {
this.head = current.next;
if (this.count === 1) {
this.tail = undefined;
} else {
this.head.prev = undefined; }}else if (index === this.count - 1) { // Remove the last element
current = this.tail;
this.tail = current.prev;
this.tail.next = undefined;
} else {
current = this.getElementAt(index);
const previous = current.prev;
previous.next = current.next;
current.next.prev = previous;
}
this.count--;
return current.element;
}
return undefined;
}
Copy the code
4. Circular linked lists
Have linked form item reference + bidirectional linked list bidirectional reference
Pointer to last element to next element (tail.next) to first element (head)
Bidirectional circular lists: tail.next to head elements and head.prev to tail elements
class CircularLinkedList extends LinkedList {
constructor(equalsFN = defaultEquals) {
super(equalsFn); }}Copy the code
insert(element, index) {
if (index >= 0 && index <= this.count) {
const node = new Node(element);
let current = this.head;
if(index === 0) { // The insertion point is the first position in the list
if (this.head == null) { // The list is empty
this.head = node;
node.next = this.head;
} else {
node.next = current; // Node's next pointer points to the head
current = this.getElementAt(this.size()); // The last element
this.head = node; // Add the element as the head of the list
current.next = this.head; // The last element points to the header}}else {
const previous = this.getElementAt(index - 1);
node.next = previous.next;
previous.next = node;
}
this.count++;
return true;
}
return false;
}
removeAt(index) {
if(index >= 0 && index < this.count) {
let current = this.head;
if(index === 0) { // Remove the first element
if(this.size() === 1) {
this.head = undefined; // There is only one element, let the header be undefined
} else {
const removed = this.head;
current = this.getElementAt(this.size()); // The last element
this.head = this.head.next; // The header element becomes the next element
current.next = this.head; // The last element, next, points to the head
current = removed; // Get the removed element, followed by return to remove the element value}}else {
const previous = this.getElementAt(index - 1);
current = previous.next;
previous.next = current.next;
}
this.count--;
return current.element;
}
return undefined;
}
Copy the code
5. Ordered lists
A list structure that keeps elements ordered
const Compare = {
LESS_THAN: -1.BIGGER_THAN: 1
};
function defaultCompare(a,b) {
if (a === b) {
return 0;
}
return a < b ? Compare.LESS_THAN : Compare.BIGGER_THAN;
}
class SortedLinkedList extends LinkedList {
constructor(equalsFn = defaultEquals, compareFn = defaultCompare) {
super(equalsFn);
this.compareFn = compareFn; }}Copy the code
insert(element, index = 0) {
if(this.isEmpty()) {
return super.insert(element,0);
}
const pos = this.getIndexNextSortedElement(element);
return super.insert(elemenet,pos);
}
getIndexNextSortedElement(element) {
let current = this.head;
let i = 0;
for(; i < this.size() && current; i++) {
const comp = this.compareFn(element,current.element);
if(comp === Compare.LESS_THAN) {
return i;
}
current = current.next;
}
return i;
}
Copy the code
6. Create StackLinkedList class
class StackLinkedList {
constructor() {
this.items = new DoublyLinkedList(); / / {1}
}
push(element) {
this.items.push(element); / / {2}
}
pop() {
if (this.isEmpty()) {
return undefined;
}
return this.items.removeAt(this.size() - 1); / / {3}}}Copy the code
7. LeetCode problem
/** * Definition for singly-linked list. * function ListNode(val, next) { * this.val = (val===undefined ? 0 : val) * this.next = (next===undefined ? null : next) * } */
/ * * *@param {ListNode} head
* @return {ListNode}* /
var reverseList = function(head) {
let p1 = head;
let p2 = null;
while(p1) {
const tmp = p1.next;
p1.next = p2; // point to the previous pointer
p2 = p1;
p1 = tmp;
}
return p2; // P1 has disappeared
};
Copy the code
General idea:
Flip the node so that n+1 next points to n
Specific operation:
Create a pair of fast and slow Pointers, p1 to the head, p2 to null (slower than p1)
When p1 exists, store p1.next as TMP, p1.next points to the previous pointer, p2 and P1 move to the right until all nodes are flipped
var addTwoNumbers = function(l1, l2) {
const l3 = new ListNode(0)
let p1 = l1
let p2 = l2
let p3 = l3
let carry = 0 // store the units digit of val
while(p1 || p2) {
const v1 = p1 ? p1.val:0
const v2 = p2 ? p2.val:0
const val = v1 + v2 + carry / / add up
carry = Math.floor(val / 10) // Retrieve ten digits
p3.next = new ListNode(val % 10) // Add the units digit
//p1, P2 go right
if(p1) p1 = p1.next
if(p2) p2 = p2.next
p3 = p3.next
}
if(carry) {
p3.next = new ListNode(carry) // Put carry in
}
return l3.next
};
Copy the code
var deleteDuplicates = function(head) {
let p = head;
while(p && p.next) {
if(p.val === p.next.val){
p.next = p.next.next;
}else{ p = p.next; }}return head;
};
Copy the code
var hasCycle = function(head) {
let slow = head;
let fast = head;
while(slow && fast && fast.next) {
slow = slow.next;
fast = fast.next.next;
if(slow === fast){
return true; }}return false;
};
Copy the code
Fast and slow pointer: when the fast and slow pointer meets, it indicates that there is a ring