Singly Linked List - Data Structures and Algorithms in Javascript

Developer with a love for web technologies. Building things with react, next and node.
Search for a command to run...

Developer with a love for web technologies. Building things with react, next and node.
No comments yet. Be the first to comment.
This series will be a complete guide to data structures and algorithms. We will start from the very basic and gradually move to the advanced data structures and algorithms.
In the fast-paced world of software development, where competition is fierce and innovation is key, having a standout portfolio is not just an advantage—it's a necessity. Your portfolio is more than a collection of projects; it's a visual narrative t...

Next.Js 14 has added a lot of cool features that make development so much easier like: App Router Server Actions Route Handlers Client and Server Components In this article, we will be covering Server Actions. What are Server Actions A Server A...

Next.js provides a solid foundation for building React applications with server-side rendering, while Supabase offers a scalable and easy-to-use backend-as-a-service with PostgreSQL as the database. Since the release of Next.js 13 and then Next.js 14...

Communication with your users is really important and emails are one of the means of communication. Sending emails is really important for applications. These are some of the reasons: User Onboarding and Account Verification Password Resets and Acc...

This is our first article in the series of Data Structures and Algorithms. In this article, we will discuss the ins and outs of a Singly Linked List.
A Singly Linked List is a linear data structure that allows us to store data in a linear way. It is a collection of nodes where each node points to the next node.

Every node contains two crucial things:
Data (integer, string, boolean, etc)
Pointer (points to the next node)
A singly linked list has two pointers of its own:
head (points to the first node)
tail (points to the last node)
The pointer of the last node always points to null since there is no node after it.
Now that we know what is a singly linked list and what it looks like, let's code it using JavaScript. We will be using object-oriented programming to implement it and we will use the ES6 Class syntax.
We will need two classes:
Node (represents the structure of the node)
SinglyLinkedList (represents the structure and also includes the major operations)
As we discussed above, a node contains two things:
Data (number, string, boolean, etc)
Pointer (points to the next node)
The pointer initially points to null.
class Node {
constructor(value) {
this.value = value
this.next = null
}
}
A singly linked list will have:
head pointer (points to the first node)
tail pointer (points to the last node)
length (number of nodes in the list)
class SinglyLinkedList {
constructor() {
this.head = null
this.tail = null
this.length = 0
}
}
A singly linked list can perform the following operations:
push (insert at the end)
pop (remove from the end)
shift (remove from the start)
unshift (insert at the start)
get (get a node at a particular index)
set (change the value of a node at a particular index)
insert (insert at a particular index)
remove (remove from a particular index)
Now we will implement all these operations into the SinglyLinkedList class.
Push will insert a new node at the end.
push(value) {
const node = new Node(value)
if (!this.length) {
this.head = node
this.tail = node
} else {
this.tail.next = node
this.tail = node
}
this.length++
return this
}
Pop will remove a node from the end.
pop() {
let currentNode = this.head
if (this.length <= 1) {
this.head = null
this.tail = null
} else {
while (!currentNode?.next?.next) {
currentNode = currentNode.next
}
currentNode.next = null
this.tail = currentNode
}
this.length--
return this
}
Shift will remove a node from the start.
shift() {
if (this.length <= 1) {
this.head = null
this.tail = null
} else {
this.head = this.head.next
}
this.length--
return this
}
Unshift will insert a new node at the start
unshift(value) {
const node = new Node(value)
if (!this.length) {
this.tail = node
} else {
node.next = this.head
}
this.head = node
this.length++
return this
}
Get a node's value from a particular index.
get(index) {
if (index < 0 || index >= this.length) return undefined
let currentNode = this.head
for (let i = 1; i <= index; i++) {
currentNode = currentNode.next
}
return currentNode.value
}
Change the node's value at a particular index.
set(index, value) {
if (index < 0 || index >= this.length) return
let currentNode = this.head
for (let i = 1; i <= index; i++) {
currentNode = currentNode.next
}
currentNode.value = value
return this
}
Insert a new node at a particular index.
insert(index, value) {
if (index < 0 || index > this.length) return this
const node = new Node(value)
if (index === 0) return this.unshift(value)
if (index === this.length) return this.push(value)
let currentNode = this.head
for (let i = 1; i <= index - 1; i++) {
currentNode = currentNode.next
}
const nextNode = currentNode.next
currentNode.next = node
node.next = nextNode
this.length++
return this
}
Remove a node at a particular index.
remove(index) {
if (index < 0 || index >= this.length) return
if (index === 0) return this.shift()
if (index === this.length - 1) return this.pop()
let currentNode = this.head
for (let i = 1; i <= index - 1; i++) {
currentNode = currentNode.next
}
currentNode.next = currentNode.next.next
this.length--
return this
}
Now that we have implemented all the basic operations that a singly linked list can perform, let's talk about the time complexity of each of them:
push: O(1)
pop: O(n)
shift: O(1)
unshift: O(1)
get: O(n)
set: O(n)
insert: O(n)
remove: O(n)
A singly linked list is useful when you want to frequently insert or remove elements because it takes constant time.
A singly linked list is not efficient when it comes to accessing the elements because there are no indices assigned to the elements. So you have to visit each node starting from the first node until you find the target node.