37
loading...
This website collects cookies to deliver better user experience
Knowledge is power and never useless.
[]
) and push as many elements you want to it.Hey, for this list here can be allocated only a few bytes because we know in advance it'll only contain a max of 3 elements
Array.prototype.splice()
.const months = ['Jan', 'March', 'April', 'June'];
// insert exactly in the index one (1, 0) the string `Feb`
months.splice(1, 0, 'Feb');
console.log(months); // Array ["Jan", "Feb", "March", "April", "June"]
// removes everything from the index 3 til the last el ("April" and "June")
months.splice(3, months.length)
console.log(months); // ["Jan", "Feb", "March"]
element
: the data we want to store in our list;next
: a link to another node or the value null (non-existing next node)..append(element)
- method used to append a new element to the end of the list;.indexOf(element)
- method used to known where in the index our element was added;.insertAt(position, element)
- method used to add an element in a specific position;.remove(element)
- method used to remove an element from the list;.removeAt(position)
- method used to remove an element in some specific position;.toString()
- method used to have an overview of our list.function LinkedListFactory() {
return {
append,
indexOf,
insertAt,
remove,
removeAt,
toString,
};
function append(element) {}
function indexOf(element) {}
function insertAt(position, element) {}
function remove(element) {}
function removeAt(position) {}
function toString() {}
}
head
- variable to hold our very first element, where everything will start. It'll start with the value null
;length
- a control variable to easily hold the list size. It'll start with the value 0
.
function LinkedListFactory() {
let head = null;
let length = 0;
return {
append,
indexOf,
insertAt,
remove,
removeAt,
toString,
};
function append(element) {}
function indexOf(element) {}
function insertAt(position, element) {}
function remove(element) {}
function removeAt(position) {}
function toString() {}
}
append
method, we first need to create an internal basic structure which we can call "node".next
will always be null
:function append(element) {
const node = {
element,
next: null
}
}
head
is null
. For this case, we'll assign our newly created node to the head:function append(element) {
const node = {
element,
next: null,
};
if (head === null) {
head = node;
}
}
.next
equal to null
.function append(element) {
const node = {
element,
next: null,
};
if (head === null) {
head = node;
} else {
let currentNode = head;
while (currentNode.next !== null) {
currentNode = currentNode.next;
}
}
}
.next
property of this element to our newly created node:function append(element) {
const node = {
element,
next: null,
};
if (head === null) {
head = node;
} else {
let currentNode = head;
while (currentNode.next !== null) {
currentNode = currentNode.next;
}
currentNode.next = node;
}
}
length
) so it's important to be outside the conditionfunction append(element) {
const node = {
element,
next: null,
};
if (head === null) {
head = node;
} else {
let currentNode = head;
while (currentNode.next !== null) {
currentNode = currentNode.next;
}
currentNode.next = node;
}
length++;
}
nodeIndex
and currentElement
. The first will be used as return value but also to know where we are in the iteration and the second to do the comparison if the element is the one we're looking for:function indexOf(element) {
let nodeIndex = 0;
let currentNode = head;
}
head
might be null
or the .next
of the last node will be null
? We'll use this condition to loop through all nodes.function indexOf(element) {
let nodeIndex = 0;
let currentNode = head;
while (currentNode) {
if (element === currentNode.element) {
return nodeIndex;
}
nodeIndex++;
currentNode = currentNode.next;
}
}
currentNode
is not null
, we'll first check if the element is the one we're looking for. If so, we can straight return the value of nodeIndex
.nodeIndex
and assign currentNode
to currentNode.next
, or in other words, simply moving to the next node to run the comparison over again.-1
but nothing stops us of returning other value like null
for example:function indexOf(element) {
let nodeIndex = 0;
let currentNode = head;
while (currentNode) {
if (element === currentNode.element) {
return nodeIndex;
}
nodeIndex++;
currentNode = currentNode.next;
}
return -1
}
indexOf
(controlling the index) plus we'll have to tweak the node connections..next
point to the element we're inserting.next
point to the element we just found .next
function insertAt(position, element) {
const isPositionInTheRange = position > -1 && position <= length;
if(!isPositionInTheRange){
return false
}
}
Tip: the variable which holds this logic is just a semantic way of describing (in English) a condition.
function insertAt(position, element) {
const isPositionInTheRange = position > -1 && position <= length;
if(!isPositionInTheRange){
return false
}
// Our brand new node
const node = {
element,
next: null
}
// Controller to iterate over the list
let currentNode = head;
}
.next
will be the current element and the head now will be the new node:function insertAt(position, element) {
const isPositionInTheRange = position > -1 && position <= length;
if (!isPositionInTheRange) {
return false;
}
const node = {
element,
next: null,
};
let currentNode = head;
const isHeadPosition = position === 0;
if (isHeadPosition) {
// Assign currentNode (head) to `node.next`
node.next = currentNode;
// Replace the current head with this node
head = node;
} else {
}
}
index
(for iterate based on that) and previousNode
(for re-create the links when we find the position):function insertAt(position, element) {
const isPositionInTheRange = position > -1 && position <= length;
if (!isPositionInTheRange) {
return false;
}
const node = {
element,
next: null,
};
let currentNode = head;
const isHeadPosition = position === 0;
if (isHeadPosition) {
node.next = currentNode;
head = node;
} else {
let previousNode = null;
let index = 0;
}
}
index
. While index is less then the desired position, we'll update our controllers previousNode
and currentNode
:function insertAt(position, element) {
const isPositionInTheRange = position > -1 && position <= length;
if (!isPositionInTheRange) {
return false;
}
const node = {
element,
next: null,
};
let currentNode = head;
const isHeadPosition = position === 0;
if (isHeadPosition) {
node.next = currentNode;
head = node;
} else {
let previousNode = null;
let index = 0;
while (index++ < position){
previousNode = currentNode;
currentNode = currentNode.next;
}
}
}
Remember: index++ will first evaluate the number and only then increment 1.
previousNode
<-> new node
<-> currentNode
:function insertAt(position, element) {
const isPositionInTheRange = position > -1 && position <= length;
if (!isPositionInTheRange) {
return false;
}
const node = {
element,
next: null,
};
let currentNode = head;
const isHeadPosition = position === 0;
if (isHeadPosition) {
node.next = currentNode;
head = node;
} else {
let previousNode = null;
let index = 0;
while (index++ < position){
previousNode = currentNode;
currentNode = currentNode.next;
}
previousNode.next = node;
node.next = currentNode;
}
}
+1
in our list length, not matter where in the list it was inserted and return true
to inform for the user that the operation succeeded:function insertAt(position, element) {
const isPositionInTheRange = position > -1 && position <= length;
if (!isPositionInTheRange) {
return false;
}
const node = {
element,
next: null,
};
let currentNode = head;
const isHeadPosition = position === 0;
if (isHeadPosition) {
node.next = currentNode;
head = node;
} else {
let previousNode = null;
let index = 0;
while (index++ < position){
previousNode = currentNode;
currentNode = currentNode.next;
}
previousNode.next = node;
node.next = currentNode;
}
length++;
return true;
}
insertAt
, we'll need to:function removeAt(position){
const isPositionInTheRange = position > -1 && position < length;
if(!isPositionInTheRange){
return null
}
}
currentNode
to iterate through:function removeAt(position){
const isPositionInTheRange = position > -1 && position < length;
if(!isPositionInTheRange){
return null
}
let currentNode = head;
}
head
to be the currentNode (in this case the head element itself) to it's .next
value:function removeAt(position){
const isPositionInTheRange = position > -1 && position < length;
if(!isPositionInTheRange){
return null
}
let currentNode = head;
if(position === 0){
head = currentNode.next;
}
}
In case you're not aware, by just removing all references from this element the garbage collector will understand that it is no longer needed and prune it from the memory.
index
and previousNode
:function removeAt(position){
const isPositionInTheRange = position > -1 && position < length;
if(!isPositionInTheRange){
return null
}
let currentNode = head;
if(position === 0){
head = currentNode.next;
} else {
let index = 0;
let previousNode = null;
}
}
function removeAt(position){
const isPositionInTheRange = position > -1 && position < length;
if(!isPositionInTheRange){
return null
}
let currentNode = head;
if(position === 0){
head = currentNode.next;
} else {
let index = 0;
let previousNode = null;
while(index++ < position){
previousNode = currentNode;
currentNode = currentNode.next
}
}
}
previousNode.next
into the currentNode.next
:function removeAt(position){
const isPositionInTheRange = position > -1 && position < length;
if(!isPositionInTheRange){
return null
}
let currentNode = head;
if(position === 0){
head = currentNode.next;
} else {
let index = 0;
let previousNode = null;
while(index++ < position){
previousNode = currentNode;
currentNode = currentNode.next
}
previousNode.next = currentNode.next;
}
}
function removeAt(position){
const isPositionInTheRange = position > -1 && position < length;
if(!isPositionInTheRange){
return null
}
let currentNode = head;
if(position === 0){
head = currentNode.next;
} else {
let index = 0;
let previousNode = null;
while(index++ < position){
previousNode = currentNode;
currentNode = currentNode.next
}
previousNode.next = currentNode.next;
}
length--;
return currentNode.element;
}
indexOf
) and also have a method to remove an element from a position (removeAt
):function remove(element){
const elementIndex = indexOf(element);
return removeAt(elementIndex);
}
function toString() {
let result = "";
let current = head;
while (current) {
result += `${current.element}${current.next ? ", " : ""}`;
current = current.next;
}
return result;
}
Obs.: This will work only for primitive values. If you want to support elements as objects
, functions
, etc. you'll need to enhance the concatenation and data parsing.
function LinkedListFactory() {
let head = null;
let length = 0;
return {
append,
indexOf,
insertAt,
remove,
removeAt,
toString,
};
function append(element) {
const node = {
element,
next: null,
};
if (head === null) {
head = node
} else {
let currentNode = head;
while (currentNode.next !== null) {
currentNode = currentNode.next;
}
currentNode.next = node;
}
length++;
}
function indexOf(element) {
let nodeIndex = 0;
let currentNode = head;
while (currentNode) {
if (element === currentNode.element) {
return nodeIndex;
}
nodeIndex++;
currentNode = currentNode.next;
}
return -1;
}
function insertAt(position, element) {
const isPositionInTheRange = position > -1 && position <= length;
if (!isPositionInTheRange) {
return false;
}
const node = {
element,
next: null,
};
let currentNode = head;
const isHeadPosition = position === 0;
if (isHeadPosition) {
node.next = currentNode;
head = node;
} else {
let previousNode = null;
let index = 0;
while (index++ < position) {
previousNode = currentNode;
currentNode = currentNode.next;
}
previousNode.next = node;
node.next = currentNode;
}
length++;
return true;
}
function removeAt(position) {
const isPositionInTheRange = position > -1 && position < length;
if (!isPositionInTheRange) {
return null;
}
let currentNode = head;
if (position === 0) {
head = currentNode.next;
} else {
let index = 0;
let previousNode = null;
while (index++ < position) {
previousNode = currentNode;
currentNode = currentNode.next;
}
previousNode.next = currentNode.next;
}
length--;
return currentNode;
}
function removeAt(position) {
const isPositionInTheRange = position > -1 && position < length;
if (!isPositionInTheRange) {
return null;
}
let currentNode = head;
if (position === 0) {
head = currentNode.next;
} else {
let index = 0;
let previousNode = null;
while (index++ < position) {
previousNode = currentNode;
currentNode = currentNode.next;
}
previousNode.next = currentNode.next;
}
length--;
return currentNode.element;
}
function remove(element) {
const elementIndex = indexOf(element);
return removeAt(elementIndex);
}
function toString() {
let result = "";
let current = head;
while (current) {
result += `${current.element}${current.next ? ", " : ""}`;
current = current.next;
}
return result;
}
}
const linkedList = LinkedListFactory();
linkedList.append(1);
linkedList.append(10);
linkedList.append(-1);
linkedList.append(40);
linkedList.append(-123);
console.log(linkedList.toString()); // 1, 10, -1, 40, -123
console.log(linkedList.removeAt(3)); // 40
console.log(linkedList.toString()); // 1, 10, -1, -123
console.log(linkedList.indexOf(1)); // 0
console.log(linkedList.remove(1)); // 1
console.log(linkedList.toString()); // 10, -1, -123