Hello there! Today, our journey leads us into the world of Linked Lists, a fundamental data structure in computer programming. Have you ever thought about how a scavenger hunt works? You have a clue at the beginning, which leads you to the next one. Each clue points you to the next one until you find your treasure. Similarly, a Linked List employs this concept - a sequence where each node points to the next one, just like clues in a scavenger hunt.
Though they store data sequentially, Linked Lists and arrays have fundamental differences. In an array, elements are stored in contiguous memory, while in a Linked List, elements (or 'nodes') can be scattered throughout memory, connected by pointers. The dynamic structure of Linked Lists enables efficient insertions and deletions at any position, benefitting applications like a photo gallery, where we frequently add, update, and delete photos.
Let's begin to understand, implement, and manipulate Linked Lists in JavaScript!
A node in a Linked List holds two types of information - data, which houses the actual value, and next
, a reference to the subsequent node in the sequence. We use JavaScript's class
to construct these nodes.
The JavaScript code below creates a Node class, providing a blueprint for every node:
JavaScript1class Node { 2 constructor(data, next = null) { 3 this.data = data; 4 this.next = next; 5 } 6}
In the above code, constructor
is a unique method for creating and initializing an object within a class. We have a data
property to hold the data and a next
property to reference the next node. We initialize next
with null
, indicating that the next node doesn't yet exist.
We start with defining the LinkedList
class storing the first node, which is called head
:
JavaScript1class LinkedList { 2 constructor() { 3 this.head = null; 4 } 5}
Now, let's move to its methods!
The append
method adds a new node at the end of the Linked List. The method takes a data parameter that is passed when creating a new node.
JavaScript1append(data) { 2 const newNode = new Node(data); 3 if (!this.head) { 4 this.head = newNode; 5 } else { 6 let currentNode = this.head; 7 while (currentNode.next) { 8 currentNode = currentNode.next; 9 } 10 currentNode.next = newNode; 11 } 12}
Initially, it checks if the head
is null (implying the list is empty); in such case, the new node becomes the head
. Otherwise, it starts from the head
and traverses to the last node (where next
is null
) and assigns the newNode
to the next
of the current node.
The addFirst
method adds a new node at the beginning of the Linked List, effectively making it the new head
of the list.
JavaScript1addFirst(data) { 2 const newNode = new Node(data); 3 newNode.next = this.head; 4 this.head = newNode; 5}
This method also takes a data parameter, creates a new node, sets the next
of newNode
to the current head
, and finally, sets newNode
as the new head
of the list.
The delete
method removes a node with a specific data value from the linked list.
JavaScript1delete(data) { 2 if (!this.head) { 3 return; 4 } 5 6 if (this.head.data === data) { 7 this.head = this.head.next; 8 return; 9 } 10 11 let current = this.head; 12 while (current.next) { 13 if (current.next.data === data) { 14 current.next = current.next.next; 15 return; 16 } 17 current = current.next; 18 } 19}
This method also handles two scenarios. If the head
node is the target node (i.e., its data matches the input data), it sets the head
to the next node. Otherwise, it iterates through the list until it finds the target node and adjusts the next
pointer of the previous node to skip the target node, effectively removing it from the list. If the target node is not found, the function completes with no changes to the list.
In a Linked List, operations take different amounts of time, depending on their nature. Complexity analysis helps us understand both this time factor and memory usage.
For instance, accessing an element in a Linked List has a time complexity of O(n) because, in the worst-case scenario, we might have to traverse through the entire list. On the other hand, if we're adding or removing a node at the beginning of the list, the operation's time complexity is O(1) and O(n) elsewhere.
Congratulations on reaching this point! You've mastered implementing, manipulating, and traversing Linked Lists in JavaScript, along with complexity analysis and utility functions.
Next, we'll take this freshly acquired knowledge for a spin in the upcoming hands-on sessions! This practice will clarify your understanding of Linked Lists as if polishing a diamond. Brace yourself!