Hello everyone! Hope you are doing good โจ
This is the first part of the Linked List Data structure where we will understand what is a linked list and its four operations. For advance operations, please read second part here
In our second article of the Data Structure 101 series, we learned about Arrays. We learned that whenever we want to store data in an organized form, we can use Arrays. But there are several reasons arrays are not always the best data structure to use for organizing data.
In many programming languages, arrays are fixed in length, so it is hard to add new data when the last element of the array is reached. Also, adding and removing data from an array is difficult because you have to move array elements up or down to reflect either an addition or a deletion.
Therefore, we need a more efficient data structure that can be used to store data in an organized form. Luckily, we have one! ๐
Definition โจ
A linked list is a collection/list of nodes. Each node is linked to a successor node in the list using a reference.
Every node has two parts:
- Data.
- Reference of next node.
Image Credits: programiz.com
Important Concept โจ
The linked list can be used in almost every situation where a one-dimensional array is used.
The first node of the linked list is called
head
.- The last node of the linked list is called
tail
. tail
has alwaysnull
as thenext
reference because it's the last element.- The
next
is always pointing to the successor node in the list.
Types Of Linked List โจ
Singly Linked List
In Singly Linked List, the node has only one reference to the next node in the list. We are going to cover it in this post.
Doubly Linked List
In Doubly Linked List, the node has two references. One to the next node and one of the previous node.
Time Complexity โจ
Operation | Time Complexity |
Insertion | O(1) |
Deletion | O(1) |
Search | O(n) |
Access | O(n) |
Space Complexity of Linked List: O(n)
Applications Of Linked List โจ
- Linked List is heavily used to create stacks and queues.
- When you need constant-time insertions/deletions from the list.
- When the size of the list is unknown. This means you don't know how much your list is going to be scaled, then use Linked List instead of Arrays.
- When you don't need random access to the elements.
- Remember Priority Queue? You can use a linked list to insert elements in between the list as we do in a priority queue.
Coding a Linked List in JavaScript โจ
Let's take a look at how to create a Linked List using my favorite language JavaScript.
Let's create a node class that is going to represent a node in the linked list.
class Node {
constructor(value) {
this.value = value;
this.next = null;
}
}
We have created a Node
class and inside the constructor of it, we have initialized two properties.
value
- The value of the node. It's the data that we want to store inside the node.next
- This will contain the reference of the next node. Initially, it's alwaysnull
.
Now that we have the Node
class in place, let's create the LinkedList
class that will contain the operations of our linked list.
class LinkedList {
constructor() {
this.head = null;
this.tail = null;
this.length = 0;
}
}
We have created a class LinkedList
and inside the constructor method, we are initializing three things.
head
: The start node or the first node of the linked list.tail
: The last node of the linked list.length
: A property to store the length of the linked list.
Let's code some operations of the linked list now! โ
push
In push
, we insert a node at the end of the linked list.
Here are the steps which we are going to follow while coding push
.
- Create a new method
push
that accepts avalue
as an argument. - Create a new node using the
Node
class with thevalue
passed in. - Check if the list is already empty?
- If the list is empty, then assign the new node to the
head
andtail
. Because right now, we have only one node that ishead
andtail
both simultaneously.
- If the list is empty, then assign the new node to the
- If the list is not empty then:
- Assign the
next
property of the currenttail
to the new node. - Assign the new node to the
tail
itself. - Increment the
length
by 1.
- Assign the
push(value) {
// Node Creation
const newNode = new Node(value);
if (!this.head) {
// check if list is empty?
this.head = newNode; // new head
this.tail = newNode; // new tail
this.length++;
return this;
}
// on the `next` of last node, add the reference to new node.
this.tail.next = newNode;
// update the last node by the new node.
this.tail = newNode;
// Increment the length;
this.length++;
return this;
}
pop
In pop
, we delete a node from the end of the linked list.
Here are the steps which we are going to follow while coding pop
.
- Create a new method
pop
that accepts nothing. - Check if the list is already empty?
- If the list is empty, then return (Nothing to be removed).
- If the list is not empty, then we have to calculate second last element because we will set the
tail
of a linked list to the second last element and remove the last one by setting the next propertynull
on the current tail. - Decrement the
length
by one. - If the
length
of the linked list is 0, that means that we have deleted everything from the linked list. So set thehead
andtail
tonull
.
pop() {
// if the head is null, then return null;
if (!this.head) {
return;
}
// calculate the second last node.
let currentNode = this.head;
let secondLastNode = this.head;
while (currentNode.next) {
secondLastNode = currentNode;
currentNode = currentNode.next;
}
// set the second last node to the new tail of the linked list.
this.tail = secondLastNode;
// set the current tail's next to null;
this.tail.next = null;
// decrement the length
this.length--;
// if the length is `this.length` 0 then reset the linked list
if (this.length === 0) {
this.head = null;
this.tail = null;
}
return this;
}
shift
In shift
, we remove a node at the start of the linked list.
Here are the steps which we are going to follow while coding shift
.
- If the
head
is empty, then return. - We will store the current
head
in a variable calledremovedHead
. - We will set the current
head
to thenext
ofremovedHead
. - Decrement the
length
by one. - If the
length
is 0, then set the tail tonull
shift() {
// check if there is no head then return;
if (!this.head) return;
// store the current head in a variable.
const removedHead = this.head;
// store the next node of head to be the current head
this.head = removedHead.next;
// decrement the length
this.length--;
// if length is 0, then reset the list
if (this.length === 0) {
this.tail = null;
this.head = null;
}
return this;
}
unshift
In unshift
, we add a node at the start of the linked list.
Here are the steps which we are going to follow while coding unshift
.
- Create a method
shift
in the class which is going to accept thevalue
of the node as an argument. - Create a new node from the
Node
class. - If the
head
is empty, then make thehead
andtail
the new node. - Set the
next
property on the new node to the currenthead
. - Set the new node as the new
head
of the linked list. - Increment the
length
by one.
unshift(value) {
// create a new node
const newNode = new Node(value);
// if the head is empty, make the new node the head and tail (first node).
if (!this.head) {
this.head = newNode;
this.tail = newNode;
this.length++;
return;
}
// Otherwise, set the next to of new node to current head
newNode.next = this.head;
// set the current head of list to new node
this.head = newNode;
// increment the length
this.length++;
return newNode;
}
That's it, folks! hope the first part was a good read for you. Thank you! โจ