mirror of
https://github.com/TheAlgorithms/Java.git
synced 2025-07-05 08:17:33 +08:00
Enhance docs, add tests in MergeKSortedLinkedList (#5995)
This commit is contained in:
@ -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)
|
||||
|
@ -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.
|
||||
*
|
||||
* <p>Example usage:
|
||||
* <pre>
|
||||
* 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);
|
||||
* </pre>
|
||||
* </p>
|
||||
*
|
||||
* <p>This class is designed to handle nodes of integer linked lists and can be expanded for additional data types if needed.</p>
|
||||
*
|
||||
* @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
|
||||
* <p>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.</p>
|
||||
*
|
||||
* @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<Node> 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<Node> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user