mirror of
https://github.com/TheAlgorithms/Java.git
synced 2025-12-19 07:00:35 +08:00
[FEAT] Implement Flattening MultiLevel LinkedList (#6670)
[FEAT] Implement Flattening Multilevel LinkedList Co-authored-by: Priyanshu1303d <priyanshu130d@gmail.com>
This commit is contained in:
committed by
GitHub
parent
a9357102b3
commit
b316dcf1c6
@@ -0,0 +1,92 @@
|
||||
package com.thealgorithms.datastructures.lists;
|
||||
/**
|
||||
* Implements an algorithm to flatten a multilevel linked list.
|
||||
*
|
||||
* In this specific problem structure, each node has a `next` pointer (to the
|
||||
* next node at the same level) and a `child` pointer (which points to the head
|
||||
* of another sorted linked list). The goal is to merge all these lists into a
|
||||
* single, vertically sorted linked list using the `child` pointer.
|
||||
*
|
||||
* The approach is a recursive one that leverages a merge utility, similar to
|
||||
* the merge step in Merge Sort. It recursively flattens the list starting from
|
||||
* the rightmost node and merges each node's child list with the already
|
||||
* flattened list to its right.
|
||||
* @see <a href="https://www.geeksforgeeks.org/flattening-a-linked-list/">GeeksforGeeks: Flattening a Linked List</a>
|
||||
*/
|
||||
public final class FlattenMultilevelLinkedList {
|
||||
/**
|
||||
* Private constructor to prevent instantiation of this utility class.
|
||||
*/
|
||||
private FlattenMultilevelLinkedList() {
|
||||
}
|
||||
/**
|
||||
* Node represents an element in the multilevel linked list. It contains the
|
||||
* integer data, a reference to the next node at the same level, and a
|
||||
* reference to the head of a child list.
|
||||
*/
|
||||
static class Node {
|
||||
int data;
|
||||
Node next;
|
||||
Node child;
|
||||
|
||||
Node(int data) {
|
||||
this.data = data;
|
||||
this.next = null;
|
||||
this.child = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges two sorted linked lists (connected via the `child` pointer).
|
||||
* This is a helper function for the main flatten algorithm.
|
||||
*
|
||||
* @param a The head of the first sorted list.
|
||||
* @param b The head of the second sorted list.
|
||||
* @return The head of the merged sorted list.
|
||||
*/
|
||||
private static Node merge(Node a, Node b) {
|
||||
// If one of the lists is empty, return the other.
|
||||
if (a == null) {
|
||||
return b;
|
||||
}
|
||||
if (b == null) {
|
||||
return a;
|
||||
}
|
||||
|
||||
Node result;
|
||||
|
||||
// Choose the smaller value as the new head.
|
||||
if (a.data < b.data) {
|
||||
result = a;
|
||||
result.child = merge(a.child, b);
|
||||
} else {
|
||||
result = b;
|
||||
result.child = merge(a, b.child);
|
||||
}
|
||||
result.next = null; // Ensure the merged list has no `next` pointers.
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flattens a multilevel linked list into a single sorted list.
|
||||
* The flattened list is connected using the `child` pointers.
|
||||
*
|
||||
* @param head The head of the top-level list (connected via `next` pointers).
|
||||
* @return The head of the fully flattened and sorted list.
|
||||
*/
|
||||
public static Node flatten(Node head) {
|
||||
// Base case: if the list is empty or has only one node, it's already flattened.
|
||||
if (head == null || head.next == null) {
|
||||
return head;
|
||||
}
|
||||
|
||||
// Recursively flatten the list starting from the next node.
|
||||
head.next = flatten(head.next);
|
||||
|
||||
// Now, merge the current list (head's child list) with the flattened rest of the list.
|
||||
head = merge(head, head.next);
|
||||
|
||||
// Return the head of the fully merged list.
|
||||
return head;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package com.thealgorithms.datastructures.lists;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
/**
|
||||
* Unit tests for the FlattenMultilevelLinkedList class.
|
||||
* This class tests the flattening logic with various list structures,
|
||||
* including null lists, simple lists, and complex multilevel lists.
|
||||
*/
|
||||
final class FlattenMultilevelLinkedListTest {
|
||||
|
||||
// A helper function to convert a flattened list (connected by child pointers)
|
||||
// into a standard Java List for easy comparison.
|
||||
private List<Integer> toList(FlattenMultilevelLinkedList.Node head) {
|
||||
List<Integer> list = new ArrayList<>();
|
||||
FlattenMultilevelLinkedList.Node current = head;
|
||||
while (current != null) {
|
||||
list.add(current.data);
|
||||
current = current.child;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Test with a null list")
|
||||
void testFlattenNullList() {
|
||||
assertNull(FlattenMultilevelLinkedList.flatten(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Test with a simple, single-level list")
|
||||
void testFlattenSingleLevelList() {
|
||||
// Create a simple list: 1 -> 2 -> 3
|
||||
FlattenMultilevelLinkedList.Node head = new FlattenMultilevelLinkedList.Node(1);
|
||||
head.next = new FlattenMultilevelLinkedList.Node(2);
|
||||
head.next.next = new FlattenMultilevelLinkedList.Node(3);
|
||||
|
||||
// Flatten the list
|
||||
FlattenMultilevelLinkedList.Node flattenedHead = FlattenMultilevelLinkedList.flatten(head);
|
||||
|
||||
// Expected output: 1 -> 2 -> 3 (vertically)
|
||||
List<Integer> expected = List.of(1, 2, 3);
|
||||
assertEquals(expected, toList(flattenedHead));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Test with a complex multilevel list")
|
||||
void testFlattenComplexMultilevelList() {
|
||||
// Create the multilevel structure from the problem description
|
||||
// 5 -> 10 -> 19 -> 28
|
||||
// | | | |
|
||||
// 7 20 22 35
|
||||
// | | |
|
||||
// 8 50 40
|
||||
// | |
|
||||
// 30 45
|
||||
FlattenMultilevelLinkedList.Node head = new FlattenMultilevelLinkedList.Node(5);
|
||||
head.child = new FlattenMultilevelLinkedList.Node(7);
|
||||
head.child.child = new FlattenMultilevelLinkedList.Node(8);
|
||||
head.child.child.child = new FlattenMultilevelLinkedList.Node(30);
|
||||
|
||||
head.next = new FlattenMultilevelLinkedList.Node(10);
|
||||
head.next.child = new FlattenMultilevelLinkedList.Node(20);
|
||||
|
||||
head.next.next = new FlattenMultilevelLinkedList.Node(19);
|
||||
head.next.next.child = new FlattenMultilevelLinkedList.Node(22);
|
||||
head.next.next.child.child = new FlattenMultilevelLinkedList.Node(50);
|
||||
|
||||
head.next.next.next = new FlattenMultilevelLinkedList.Node(28);
|
||||
head.next.next.next.child = new FlattenMultilevelLinkedList.Node(35);
|
||||
head.next.next.next.child.child = new FlattenMultilevelLinkedList.Node(40);
|
||||
head.next.next.next.child.child.child = new FlattenMultilevelLinkedList.Node(45);
|
||||
|
||||
// Flatten the list
|
||||
FlattenMultilevelLinkedList.Node flattenedHead = FlattenMultilevelLinkedList.flatten(head);
|
||||
|
||||
// Expected sorted output
|
||||
List<Integer> expected = List.of(5, 7, 8, 10, 19, 20, 22, 28, 30, 35, 40, 45, 50);
|
||||
assertEquals(expected, toList(flattenedHead));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Test with some empty child lists")
|
||||
void testFlattenWithEmptyChildLists() {
|
||||
// Create a list: 5 -> 10 -> 12
|
||||
// | |
|
||||
// 7 11
|
||||
// |
|
||||
// 9
|
||||
FlattenMultilevelLinkedList.Node head = new FlattenMultilevelLinkedList.Node(5);
|
||||
head.child = new FlattenMultilevelLinkedList.Node(7);
|
||||
head.child.child = new FlattenMultilevelLinkedList.Node(9);
|
||||
|
||||
head.next = new FlattenMultilevelLinkedList.Node(10); // No child list
|
||||
head.next.child = null;
|
||||
|
||||
head.next.next = new FlattenMultilevelLinkedList.Node(12);
|
||||
head.next.next.child = new FlattenMultilevelLinkedList.Node(16);
|
||||
|
||||
// Flatten the list
|
||||
FlattenMultilevelLinkedList.Node flattenedHead = FlattenMultilevelLinkedList.flatten(head);
|
||||
|
||||
// Expected sorted output
|
||||
List<Integer> expected = List.of(5, 7, 9, 10, 12, 16);
|
||||
assertEquals(expected, toList(flattenedHead));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user