Given a Linked List of size N, where every node represents a sub-linked-list and contains two pointers:
(i) a next pointer to the next node,
(ii) a bottom pointer to a linked list where this node is head.
Each of the sub-linked-list is in sorted order.
Flatten the Link List such that all the nodes appear in a single level while maintaining the sorted order.
Note: The flattened list will be printed using the bottom pointer instead of next pointer.
Note: All linked lists are sorted and the resultant linked list should also be sorted
Examples:
Input: 5 -> 10 -> 19 -> 28
| | | |
V V V V
7 20 22 35
| | |
V V V
8 50 40
| |
V V
30 45
Output: 5->7->8->10->19->20->22->28->30->35->40->45->50
Input: 3 -> 10 -> 7 -> 14
| | | |
V V V V
9 47 15 22
| |
V V
17 30
Output: 3->7->9->10->14->15->17->22->30->47
The idea is to use the Merge() process of merge sort for linked lists. Use merge() to merge lists one by one, recursively merge() the current list with the already flattened list. The bottom pointer is used to link nodes of the flattened list.
Follow the given steps to solve the problem:
- Recursively call to merge the current linked list with the next linked list
- If the current linked list is empty or there is no next linked list then return the current linked list (Base Case)
- Start merging the linked lists, starting from the last linked list
- After merging the current linked list with the next linked list, return the head node of the current linked list
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
class Node {
public :
int data;
Node *next, *bottom;
};
Node* head = NULL;
Node* merge(Node* a, Node* b)
{
if (a == NULL)
return b;
if (b == NULL)
return a;
Node* result;
if (a->data < b->data) {
result = a;
result->bottom = merge(a->bottom, b);
}
else {
result = b;
result->bottom = merge(a, b->bottom);
}
result->next = NULL;
return result;
}
Node* flatten(Node* root)
{
if (root == NULL || root->next == NULL)
return root;
root->next = flatten(root->next);
root = merge(root, root->next);
return root;
}
Node* push(Node* head_ref, int data)
{
Node* new_node = new Node();
new_node->data = data;
new_node->next = NULL;
new_node->bottom = head_ref;
head_ref = new_node;
return head_ref;
}
void printList()
{
Node* temp = head;
while (temp != NULL) {
cout << temp->data << " " ;
temp = temp->bottom;
}
cout << endl;
}
int main()
{
head = push(head, 30);
head = push(head, 8);
head = push(head, 7);
head = push(head, 5);
head->next = push(head->next, 20);
head->next = push(head->next, 10);
head->next->next = push(head->next->next, 50);
head->next->next = push(head->next->next, 22);
head->next->next = push(head->next->next, 19);
head->next->next->next
= push(head->next->next->next, 45);
head->next->next->next
= push(head->next->next->next, 40);
head->next->next->next
= push(head->next->next->next, 35);
head->next->next->next
= push(head->next->next->next, 28);
head = flatten(head);
printList();
return 0;
}
|
Java
class LinkedList {
Node head;
class Node {
int data;
Node next, bottom;
Node( int data)
{
this .data = data;
next = null ;
bottom = null ;
}
}
Node merge(Node a, Node b)
{
if (a == null )
return b;
if (b == null )
return a;
Node result;
if (a.data < b.data) {
result = a;
result.bottom = merge(a.bottom, b);
}
else {
result = b;
result.bottom = merge(a, b.bottom);
}
result.next = null ;
return result;
}
Node flatten(Node root)
{
if (root == null || root.next == null )
return root;
root.next = flatten(root.next);
root = merge(root, root.next);
return root;
}
Node push(Node head_ref, int data)
{
Node new_node = new Node(data);
new_node.bottom = head_ref;
head_ref = new_node;
return head_ref;
}
void printList()
{
Node temp = head;
while (temp != null ) {
System.out.print(temp.data + " " );
temp = temp.bottom;
}
System.out.println();
}
public static void main(String args[])
{
LinkedList L = new LinkedList();
L.head = L.push(L.head, 30 );
L.head = L.push(L.head, 8 );
L.head = L.push(L.head, 7 );
L.head = L.push(L.head, 5 );
L.head.next = L.push(L.head.next, 20 );
L.head.next = L.push(L.head.next, 10 );
L.head.next.next = L.push(L.head.next.next, 50 );
L.head.next.next = L.push(L.head.next.next, 22 );
L.head.next.next = L.push(L.head.next.next, 19 );
L.head.next.next.next
= L.push(L.head.next.next.next, 45 );
L.head.next.next.next
= L.push(L.head.next.next.next, 40 );
L.head.next.next.next
= L.push(L.head.next.next.next, 35 );
L.head.next.next.next
= L.push(L.head.next.next.next, 28 );
L.head = L.flatten(L.head);
L.printList();
}
}
|
Python3
class Node():
def __init__( self , data):
self .data = data
self . next = None
self .bottom = None
class LinkedList():
def __init__( self ):
self .head = None
def push( self , head_ref, data):
new_node = Node(data)
new_node.bottom = head_ref
head_ref = new_node
return head_ref
def printList( self ):
temp = self .head
while (temp ! = None ):
print (temp.data, end = " " )
temp = temp.bottom
print ()
def merge( self , a, b):
if (a = = None ):
return b
if (b = = None ):
return a
result = None
if (a.data < b.data):
result = a
result.bottom = self .merge(a.bottom, b)
else :
result = b
result.bottom = self .merge(a, b.bottom)
result. next = None
return result
def flatten( self , root):
if (root = = None or root. next = = None ):
return root
root. next = self .flatten(root. next )
root = self .merge(root, root. next )
return root
if __name__ = = '__main__' :
L = LinkedList()
L.head = L.push(L.head, 30 )
L.head = L.push(L.head, 8 )
L.head = L.push(L.head, 7 )
L.head = L.push(L.head, 5 )
L.head. next = L.push(L.head. next , 20 )
L.head. next = L.push(L.head. next , 10 )
L.head. next . next = L.push(L.head. next . next , 50 )
L.head. next . next = L.push(L.head. next . next , 22 )
L.head. next . next = L.push(L.head. next . next , 19 )
L.head. next . next . next = L.push(L.head. next . next . next , 45 )
L.head. next . next . next = L.push(L.head. next . next . next , 40 )
L.head. next . next . next = L.push(L.head. next . next . next , 35 )
L.head. next . next . next = L.push(L.head. next . next . next , 28 )
L.head = L.flatten(L.head)
L.printList()
|
C#
using System;
public class List {
Node head;
public
class Node {
public
int data;
public
Node next,
bottom;
public
Node( int data)
{
this .data = data;
next = null ;
bottom = null ;
}
}
Node merge(Node a, Node b)
{
if (a == null )
return b;
if (b == null )
return a;
Node result;
if (a.data < b.data) {
result = a;
result.bottom = merge(a.bottom, b);
}
else {
result = b;
result.bottom = merge(a, b.bottom);
}
result.next = null ;
return result;
}
Node flatten(Node root)
{
if (root == null || root.next == null )
return root;
root.next = flatten(root.next);
root = merge(root, root.next);
return root;
}
Node Push(Node head_ref, int data)
{
Node new_node = new Node(data);
new_node.bottom = head_ref;
head_ref = new_node;
return head_ref;
}
void printList()
{
Node temp = head;
while (temp != null ) {
Console.Write(temp.data + " " );
temp = temp.bottom;
}
Console.WriteLine();
}
public static void Main(String[] args)
{
List L = new List();
L.head = L.Push(L.head, 30);
L.head = L.Push(L.head, 8);
L.head = L.Push(L.head, 7);
L.head = L.Push(L.head, 5);
L.head.next = L.Push(L.head.next, 20);
L.head.next = L.Push(L.head.next, 10);
L.head.next.next = L.Push(L.head.next.next, 50);
L.head.next.next = L.Push(L.head.next.next, 22);
L.head.next.next = L.Push(L.head.next.next, 19);
L.head.next.next.next
= L.Push(L.head.next.next.next, 45);
L.head.next.next.next
= L.Push(L.head.next.next.next, 40);
L.head.next.next.next
= L.Push(L.head.next.next.next, 35);
L.head.next.next.next
= L.Push(L.head.next.next.next, 28);
L.head = L.flatten(L.head);
L.printList();
}
}
|
Javascript
var head;
class Node {
constructor(val) {
this .data = val;
this .bottom = null ;
this .next = null ;
}
}
function merge(a, b) {
if (a == null )
return b;
if (b == null )
return a;
var result;
if (a.data < b.data) {
result = a;
result.bottom = merge(a.bottom, b);
}
else {
result = b;
result.bottom = merge(a, b.bottom);
}
result.next = null ;
return result;
}
function flatten(root) {
if (root == null || root.next == null )
return root;
root.next = flatten(root.next);
root = merge(root, root.next);
return root;
}
function push(head_ref , data) {
var new_node = new Node(data);
new_node.bottom = head_ref;
head_ref = new_node;
return head_ref;
}
function printList() {
var temp = head;
while (temp != null ) {
document.write(temp.data + " " );
temp = temp.bottom;
}
document.write();
}
head = push(head, 30);
head = push(head, 8);
head = push(head, 7);
head = push(head, 5);
head.next = push(head.next, 20);
head.next = push(head.next, 10);
head.next.next = push(head.next.next, 50);
head.next.next = push(head.next.next, 22);
head.next.next = push(head.next.next, 19);
head.next.next.next = push(head.next.next.next, 45);
head.next.next.next = push(head.next.next.next, 40);
head.next.next.next = push(head.next.next.next, 35);
head.next.next.next = push(head.next.next.next, 20);
head = flatten(head);
printList();
|
Output
5 7 8 10 19 20 20 22 30 35 40 45 50
Time Complexity: O(N * N * M) – where N is the no of nodes in the main linked list and M is the no of nodes in a single sub-linked list
Auxiliary Space: O(1)
Explanation: As we are merging 2 lists at a time,
- After adding the first 2 lists, the time taken will be O(M+M) = O(2M).
- Then we will merge another list to above merged list -> time = O(2M + M) = O(3M).
- Then we will merge another list -> time = O(3M + M).
- We will keep merging lists to previously merged lists until all lists are merged.
- Total time taken will be O(2M + 3M + 4M + …. N*M) = (2 + 3 + 4 + … + N) * M
- Using arithmetic sum formula: time = O((N * N + N – 2) * M/2)
- The above expression is roughly equal to O(N * N * M) for a large value of N
Auxiliary Space: O(N*M) – because of the recursion. The recursive functions will use a recursive stack of a size equivalent to a total number of elements in the lists, which is N*M.
Flattening a Linked List using Priority Queues:
The idea is, to build a Min-Heap and push head node of every linked list into it and then use Extract-min function to get minimum element from priority queue and then move forward in that linked list.
Follow the given steps to solve the problem:
- Create a priority queue(Min-Heap) and push the head node of every linked list into it
- While the priority queue is not empty, extract the minimum value node from it and if there is a next node linked to the minimum value node then push it into the priority queue
- Also, print the value of the node every time after extracting the minimum value node
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
struct Node {
int data;
struct Node* next;
struct Node* bottom;
Node( int x)
{
data = x;
next = NULL;
bottom = NULL;
}
};
struct mycomp {
bool operator()(Node* a, Node* b)
{
return a->data > b->data;
}
};
void flatten(Node* root)
{
priority_queue<Node*, vector<Node*>, mycomp> p;
while (root != NULL) {
p.push(root);
root = root->next;
}
while (!p.empty()) {
auto k = p.top();
p.pop();
cout << k->data << " " ;
if (k->bottom)
p.push(k->bottom);
}
}
int main( void )
{
Node* head = new Node(5);
auto temp = head;
auto bt = head;
bt->bottom = new Node(7);
bt->bottom->bottom = new Node(8);
bt->bottom->bottom->bottom = new Node(30);
temp->next = new Node(10);
temp = temp->next;
bt = temp;
bt->bottom = new Node(20);
temp->next = new Node(19);
temp = temp->next;
bt = temp;
bt->bottom = new Node(22);
bt->bottom->bottom = new Node(50);
temp->next = new Node(28);
temp = temp->next;
bt = temp;
bt->bottom = new Node(35);
bt->bottom->bottom = new Node(40);
bt->bottom->bottom->bottom = new Node(45);
flatten(head);
cout << endl;
return 0;
}
|
Java
import java.util.PriorityQueue;
class Node {
int data;
Node next;
Node bottom;
Node( int data)
{
this .data = data;
next = null ;
bottom = null ;
}
}
class NodeComparator implements java.util.Comparator<Node> {
@Override public int compare(Node a, Node b)
{
return a.data - b.data;
}
}
public class Main {
public static void flatten(Node root)
{
PriorityQueue<Node> pq
= new PriorityQueue<Node>( new NodeComparator());
while (root != null ) {
pq.add(root);
root = root.next;
}
while (!pq.isEmpty()) {
Node k = pq.poll();
System.out.print(k.data + " " );
if (k.bottom != null ) {
pq.add(k.bottom);
}
}
}
public static void main(String[] args)
{
Node head = new Node( 5 );
Node temp = head;
Node bt = head;
bt.bottom = new Node( 7 );
bt.bottom.bottom = new Node( 8 );
bt.bottom.bottom.bottom = new Node( 30 );
temp.next = new Node( 10 );
temp = temp.next;
bt = temp;
bt.bottom = new Node( 20 );
temp.next = new Node( 19 );
temp = temp.next;
bt = temp;
bt.bottom = new Node( 22 );
bt.bottom.bottom = new Node( 50 );
temp.next = new Node( 28 );
temp = temp.next;
bt = temp;
bt.bottom = new Node( 35 );
bt.bottom.bottom = new Node( 40 );
bt.bottom.bottom.bottom = new Node( 45 );
flatten(head);
}
}
|
Python3
from heapq import heappush, heappop
class Node:
def __init__( self , d):
self .data = d
self .right = self .down = None
class LinkedList():
def __init__( self ):
self .head = None
def push( self , head_ref, data):
new_node = Node(data)
new_node.down = head_ref
head_ref = new_node
return head_ref
def printList( self ):
temp = self .head
while (temp ! = None ):
print (temp.data, end = " " )
temp = temp.down
print ()
class Cmp :
def __init__( self , node):
self .node = node
def __lt__( self , other):
return self .node.data < other.node.data
def flatten(root):
pq = []
while root:
heappush(pq, Cmp (root))
root = root.right
dummy = Node( 0 )
temp = dummy
while pq:
node = heappop(pq).node
temp.down = node
temp = node
if node.down:
heappush(pq, Cmp (node.down))
return dummy.down
if __name__ = = '__main__' :
L = LinkedList()
L.head = L.push(L.head, 30 )
L.head = L.push(L.head, 8 )
L.head = L.push(L.head, 7 )
L.head = L.push(L.head, 5 )
L.head.right = L.push(L.head.right, 20 )
L.head.right = L.push(L.head.right, 10 )
L.head.right.right = L.push(L.head.right.right, 50 )
L.head.right.right = L.push(L.head.right.right, 22 )
L.head.right.right = L.push(L.head.right.right, 19 )
L.head.right.right.right = L.push(L.head.right.right.right, 45 )
L.head.right.right.right = L.push(L.head.right.right.right, 40 )
L.head.right.right.right = L.push(L.head.right.right.right, 35 )
L.head.right.right.right = L.push(L.head.right.right.right, 20 )
flatten(L.head)
L.printList()
|
C#
using System;
using System.Collections.Generic;
public class Node {
public int data;
public Node next;
public Node bottom;
public Node( int x) {
data = x;
next = null ;
bottom = null ;
}
}
public class MyComp : IComparer<Node> {
public int Compare(Node a, Node b) {
return a.data.CompareTo(b.data);
}
}
public class Program {
public static void Flatten(Node root) {
var p = new PriorityQueue<Node>( new MyComp());
while (root != null ) {
p.Push(root);
root = root.next;
}
while (!p.Empty()) {
var k = p.Top();
p.Pop();
Console.Write(k.data + " " );
if (k.bottom != null )
p.Push(k.bottom);
}
}
public class PriorityQueue<T> {
private List<T> queue;
private IComparer<T> comparer;
public PriorityQueue(IComparer<T> comparer) {
queue = new List<T>();
this .comparer = comparer;
}
public void Push(T element) {
queue.Add(element);
Sort();
}
public T Pop() {
var element = queue[0];
queue.RemoveAt(0);
return element;
}
public T Top() {
return queue[0];
}
public int Size() {
return queue.Count;
}
public bool Empty() {
return queue.Count == 0;
}
private void Sort() {
queue.Sort(comparer);
}
}
public static void Main() {
var head = new Node(5);
var temp = head;
var bt = head;
bt.bottom = new Node(7);
bt.bottom.bottom = new Node(8);
bt.bottom.bottom.bottom = new Node(30);
temp.next = new Node(10);
temp = temp.next;
bt = temp;
bt.bottom = new Node(20);
temp.next = new Node(19);
temp = temp.next;
bt = temp;
bt.bottom = new Node(22);
bt.bottom.bottom = new Node(50);
temp.next = new Node(28);
temp = temp.next;
bt = temp;
bt.bottom = new Node(35);
bt.bottom.bottom = new Node(40);
bt.bottom.bottom.bottom = new Node(45);
Flatten(head);
Console.WriteLine();
}
}
|
Javascript
class Node {
constructor(x) {
this .data = x;
this .next = null ;
this .bottom = null ;
}
}
function mycomp(a, b) {
return a.data > b.data;
}
function flatten(root) {
const p = new PriorityQueue((a, b) => a.data - b.data);
while (root != null ) {
p.push(root);
root = root.next;
}
while (p.length !== 0) {
const k = p.pop();
if (k !== undefined) {
process.stdout.write(`${k.data} `);
if (k.bottom) p.push(k.bottom);
}
}
}
class PriorityQueue {
constructor(comparator = (a, b) => a - b) {
this .heap = [];
this .comparator = comparator;
}
get size() {
return this .heap.length;
}
isEmpty() {
return this .size === 0;
}
peek() {
return this .heap[0];
}
push(...values) {
values.forEach(value => {
this .heap.push(value);
this .bubbleUp( this .heap.length - 1);
});
}
pop() {
const root = this .heap[0];
const last = this .heap.pop();
if ( this .size > 0) {
this .heap[0] = last;
this .bubbleDown(0);
}
return root;
}
bubbleUp(index) {
while (index > 0) {
const parent = (index - 1) >> 1;
if ( this .comparator( this .heap[index], this .heap[parent]) < 0) {
[ this .heap[index], this .heap[parent]] = [ this .heap[parent], this .heap[index]];
index = parent;
} else {
break ;
}
}
}
bubbleDown(index) {
const last = this .heap.length - 1;
while ( true ) {
const left = (index << 1) + 1;
const right = left + 1;
let min = index;
if (left <= last && this .comparator( this .heap[left], this .heap[min]) < 0) {
min = left;
}
if (right <= last && this .comparator( this .heap[right], this .heap[min]) < 0) {
min = right;
}
if (min !== index) {
[ this .heap[index], this .heap[min]] = [ this .heap[min], this .heap[index]];
index = min;
} else {
break ;
}
}
}
}
( function main() {
let head = new Node(5);
let temp = head;
let bt = head;
bt.bottom = new Node(7);
bt.bottom.bottom = new Node(8);
bt.bottom.bottom.bottom = new Node(30);
temp.next = new Node(10);
temp = temp.next;
bt = temp;
bt.bottom = new Node(20);
temp.next = new Node(19);
temp = temp.next;
bt = temp;
bt.bottom = new Node(22);
bt.bottom.bottom = new Node(50);
temp.next = new Node(28);
temp = temp.next;
bt = temp;
bt.bottom = new Node(35);
bt.bottom.bottom = new Node(40);
bt.bottom.bottom.bottom = new Node(45);
flatten(head);
console.log();
})();
|
Output
5 7 8 10 19 20 22 28 30 35 40 45 50
Time Complexity: O(N * M * log(N)) – where N is the no of nodes in the main linked list (reachable using the next pointer) and M is the no of nodes in a single sub-linked list (reachable using a bottom pointer).
Auxiliary Space: O(N) – where N is the no of nodes in the main linked list (reachable using the next pointer).
NOTE: In the above explanation, k means the Node which contains the minimum element.
Last Updated :
04 Dec, 2023
Like Article
Save Article
Share your thoughts in the comments
Please Login to comment...