diff --git a/DIRECTORY.md b/DIRECTORY.md
index 95805ff41..820b80cde 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -830,6 +830,7 @@
* lists
* [CircleLinkedListTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/lists/CircleLinkedListTest.java)
* [CreateAndDetectLoopTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/lists/CreateAndDetectLoopTest.java)
+ * [MergeKSortedLinkedListTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/lists/MergeKSortedLinkedListTest.java)
* [MergeSortedArrayListTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/lists/MergeSortedArrayListTest.java)
* [MergeSortedSinglyLinkedListTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/lists/MergeSortedSinglyLinkedListTest.java)
* [QuickSortLinkedListTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/lists/QuickSortLinkedListTest.java)
diff --git a/src/main/java/com/thealgorithms/datastructures/lists/MergeKSortedLinkedList.java b/src/main/java/com/thealgorithms/datastructures/lists/MergeKSortedLinkedList.java
index 0eac20d2e..0f5c50530 100644
--- a/src/main/java/com/thealgorithms/datastructures/lists/MergeKSortedLinkedList.java
+++ b/src/main/java/com/thealgorithms/datastructures/lists/MergeKSortedLinkedList.java
@@ -1,51 +1,94 @@
package com.thealgorithms.datastructures.lists;
-import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;
/**
+ * The MergeKSortedLinkedList class provides a method to merge multiple sorted linked lists
+ * into a single sorted linked list.
+ * This implementation uses a min-heap (priority queue) to efficiently
+ * find the smallest node across all lists, thus optimizing the merge process.
+ *
+ *
Example usage:
+ *
+ * Node list1 = new Node(1, new Node(4, new Node(5)));
+ * Node list2 = new Node(1, new Node(3, new Node(4)));
+ * Node list3 = new Node(2, new Node(6));
+ * Node[] lists = { list1, list2, list3 };
+ *
+ * MergeKSortedLinkedList merger = new MergeKSortedLinkedList();
+ * Node mergedHead = merger.mergeKList(lists, lists.length);
+ *
+ *
+ *
+ * This class is designed to handle nodes of integer linked lists and can be expanded for additional data types if needed.
+ *
* @author Arun Pandey (https://github.com/pandeyarun709)
*/
public class MergeKSortedLinkedList {
/**
- * This function merge K sorted LinkedList
+ * Merges K sorted linked lists into a single sorted linked list.
*
- * @param a array of LinkedList
- * @param n size of array
- * @return node
+ * This method uses a priority queue (min-heap) to repeatedly extract the smallest node from the heads of all the lists,
+ * then inserts the next node from that list into the heap. The process continues until all nodes have been processed,
+ * resulting in a fully merged and sorted linked list.
+ *
+ * @param a Array of linked list heads to be merged.
+ * @param n Number of linked lists.
+ * @return Head of the merged sorted linked list.
*/
Node mergeKList(Node[] a, int n) {
- // Min Heap
- PriorityQueue min = new PriorityQueue<>(Comparator.comparingInt(x -> x.data));
+ if (a == null || n == 0) {
+ return null;
+ }
- // adding head of all linkedList in min heap
- min.addAll(Arrays.asList(a).subList(0, n));
+ // Min Heap to store nodes based on their values for efficient retrieval of the smallest element.
+ PriorityQueue minHeap = new PriorityQueue<>(Comparator.comparingInt(x -> x.data));
+
+ // Initialize the min-heap with the head of each non-null linked list
+ for (Node node : a) {
+ if (node != null) {
+ minHeap.add(node);
+ }
+ }
+
+ // Start merging process
+ Node head = minHeap.poll(); // Smallest head is the initial head of the merged list
+ if (head != null && head.next != null) {
+ minHeap.add(head.next);
+ }
- // Make new head among smallest heads in K linkedList
- Node head = min.poll();
- min.add(head.next);
Node curr = head;
-
- // merging LinkedList
- while (!min.isEmpty()) {
- Node temp = min.poll();
+ while (!minHeap.isEmpty()) {
+ Node temp = minHeap.poll();
curr.next = temp;
curr = temp;
- // Add Node in min Heap only if temp.next is not null
+ // Add the next node in the current list to the heap if it exists
if (temp.next != null) {
- min.add(temp.next);
+ minHeap.add(temp.next);
}
}
return head;
}
- private final class Node {
+ /**
+ * Represents a node in the linked list.
+ */
+ static class Node {
+ int data;
+ Node next;
- private int data;
- private Node next;
+ Node(int data) {
+ this.data = data;
+ this.next = null;
+ }
+
+ Node(int data, Node next) {
+ this.data = data;
+ this.next = next;
+ }
}
}
diff --git a/src/test/java/com/thealgorithms/datastructures/lists/MergeKSortedLinkedListTest.java b/src/test/java/com/thealgorithms/datastructures/lists/MergeKSortedLinkedListTest.java
new file mode 100644
index 000000000..99a890112
--- /dev/null
+++ b/src/test/java/com/thealgorithms/datastructures/lists/MergeKSortedLinkedListTest.java
@@ -0,0 +1,93 @@
+package com.thealgorithms.datastructures.lists;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import com.thealgorithms.datastructures.lists.MergeKSortedLinkedList.Node;
+import java.util.Arrays;
+import org.junit.jupiter.api.Test;
+
+class MergeKSortedLinkedListTest {
+
+ @Test
+ void testMergeKLists() {
+ Node list1 = new Node(1, new Node(4, new Node(5)));
+ Node list2 = new Node(1, new Node(3, new Node(4)));
+ Node list3 = new Node(2, new Node(6));
+ Node[] lists = {list1, list2, list3};
+
+ MergeKSortedLinkedList merger = new MergeKSortedLinkedList();
+ Node mergedHead = merger.mergeKList(lists, lists.length);
+
+ int[] expectedValues = {1, 1, 2, 3, 4, 4, 5, 6};
+ int[] actualValues = getListValues(mergedHead);
+ assertArrayEquals(expectedValues, actualValues, "Merged list values do not match the expected sorted order.");
+ }
+
+ @Test
+ void testMergeEmptyLists() {
+ Node[] lists = {null, null, null};
+
+ MergeKSortedLinkedList merger = new MergeKSortedLinkedList();
+ Node mergedHead = merger.mergeKList(lists, lists.length);
+
+ assertNull(mergedHead, "Merged list should be null when all input lists are empty.");
+ }
+
+ @Test
+ void testMergeSingleList() {
+ Node list1 = new Node(1, new Node(3, new Node(5)));
+ Node[] lists = {list1};
+
+ MergeKSortedLinkedList merger = new MergeKSortedLinkedList();
+ Node mergedHead = merger.mergeKList(lists, lists.length);
+
+ int[] expectedValues = {1, 3, 5};
+ int[] actualValues = getListValues(mergedHead);
+ assertArrayEquals(expectedValues, actualValues, "Merged list should match the single input list when only one list is provided.");
+ }
+
+ @Test
+ void testMergeListsOfDifferentLengths() {
+ Node list1 = new Node(1, new Node(3, new Node(5)));
+ Node list2 = new Node(2, new Node(4));
+ Node list3 = new Node(6);
+ Node[] lists = {list1, list2, list3};
+
+ MergeKSortedLinkedList merger = new MergeKSortedLinkedList();
+ Node mergedHead = merger.mergeKList(lists, lists.length);
+
+ int[] expectedValues = {1, 2, 3, 4, 5, 6};
+ int[] actualValues = getListValues(mergedHead);
+ assertArrayEquals(expectedValues, actualValues, "Merged list values do not match expected sorted order for lists of different lengths.");
+ }
+
+ @Test
+ void testMergeSingleElementLists() {
+ Node list1 = new Node(1);
+ Node list2 = new Node(3);
+ Node list3 = new Node(2);
+ Node[] lists = {list1, list2, list3};
+
+ MergeKSortedLinkedList merger = new MergeKSortedLinkedList();
+ Node mergedHead = merger.mergeKList(lists, lists.length);
+
+ int[] expectedValues = {1, 2, 3};
+ int[] actualValues = getListValues(mergedHead);
+ assertArrayEquals(expectedValues, actualValues, "Merged list values do not match expected sorted order for single-element lists.");
+ }
+
+ /**
+ * Helper method to extract values from the linked list into an array for assertion.
+ */
+ private int[] getListValues(Node head) {
+ int[] values = new int[100]; // assuming max length for simplicity
+ int i = 0;
+ Node curr = head;
+ while (curr != null) {
+ values[i++] = curr.data;
+ curr = curr.next;
+ }
+ return Arrays.copyOf(values, i); // return only filled part
+ }
+}