Learn how to merge two sorted linked lists into a single sorted linked list using JavaScript. Understand the algorithm, handle edge cases, and optimize your code for efficiency.
Merging linked lists is a fundamental operation in computer science, often used in various applications such as merging sorted data streams, implementing efficient data storage systems, and solving complex algorithmic problems. In this section, we will explore how to merge two sorted linked lists into a single sorted linked list using JavaScript. We will delve into the algorithm, discuss edge cases, and provide practical code examples to solidify your understanding.
The problem of merging two sorted linked lists can be stated as follows:
Given two sorted linked lists, merge them into a single sorted linked list.
This problem is a classic example of a divide-and-conquer strategy, where we take two smaller sorted lists and combine them into a larger sorted list. The key challenge is to maintain the sorted order while efficiently merging the lists.
Before diving into the implementation, let’s review some key concepts:
To merge two sorted linked lists, we can use a straightforward iterative approach. The idea is to traverse both lists simultaneously, comparing the current nodes, and appending the smaller node to the result list. Let’s implement this in JavaScript:
class ListNode {
constructor(value = 0, next = null) {
this.value = value;
this.next = next;
}
}
function mergeLists(l1, l2) {
let dummy = new ListNode(0);
let current = dummy;
while (l1 && l2) {
if (l1.value < l2.value) {
current.next = l1;
l1 = l1.next;
} else {
current.next = l2;
l2 = l2.next;
}
current = current.next;
}
// Attach the remaining nodes
current.next = l1 || l2;
return dummy.next;
}
Dummy Node: We use a dummy node to simplify edge cases. This node acts as a placeholder to start building the merged list, allowing us to easily return the head of the merged list at the end.
Comparison and Merging: We iterate through both lists, comparing the current nodes. The smaller node is appended to the current.next
, and we advance the pointer of the list from which the node was taken.
Handling Remaining Nodes: Once one of the lists is exhausted, we attach the remaining nodes of the other list to the current.next
. This ensures that all nodes are included in the merged list.
Return the Merged List: We return dummy.next
as the head of the merged list, effectively skipping the dummy node.
When merging linked lists, it’s crucial to handle edge cases to ensure robustness:
null
if both are empty.The time complexity of the merging operation is O(n + m), where n and m are the lengths of the two lists. This is because we traverse each list once, performing constant-time operations for each node.
Let’s validate our implementation with some examples and test cases:
// Helper function to create a linked list from an array
function createLinkedList(arr) {
let dummy = new ListNode(0);
let current = dummy;
for (let value of arr) {
current.next = new ListNode(value);
current = current.next;
}
return dummy.next;
}
// Test case 1: Both lists are non-empty
let list1 = createLinkedList([1, 3, 5]);
let list2 = createLinkedList([2, 4, 6]);
let mergedList = mergeLists(list1, list2);
console.log(mergedList); // Output: 1 -> 2 -> 3 -> 4 -> 5 -> 6
// Test case 2: One list is empty
list1 = createLinkedList([]);
list2 = createLinkedList([1, 2, 3]);
mergedList = mergeLists(list1, list2);
console.log(mergedList); // Output: 1 -> 2 -> 3
// Test case 3: Both lists are empty
list1 = createLinkedList([]);
list2 = createLinkedList([]);
mergedList = mergeLists(list1, list2);
console.log(mergedList); // Output: null
// Test case 4: Lists of different lengths
list1 = createLinkedList([1, 2, 3]);
list2 = createLinkedList([4, 5, 6, 7, 8]);
mergedList = mergeLists(list1, list2);
console.log(mergedList); // Output: 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8
To better understand the merging process, let’s visualize it using a diagram:
graph TD; A[Start] --> B{Compare l1 and l2}; B -->|l1 < l2| C[Attach l1 to current]; B -->|l1 >= l2| D[Attach l2 to current]; C --> E[Advance l1]; D --> F[Advance l2]; E --> G{End of l1 or l2?}; F --> G; G -->|No| B; G -->|Yes| H[Attach remaining nodes]; H --> I[Return merged list];
By mastering the technique of merging linked lists, you enhance your ability to solve complex data manipulation problems efficiently. This skill is not only valuable in technical interviews but also in real-world applications where data merging is a common requirement.