Sort numbers stored on different machines
Given N machines. Each machine contains some numbers in sorted form. But the amount of numbers, each machine has is not fixed. Output the numbers from all the machine in sorted non-decreasing form.
Example:
Machine M1 contains 3 numbers: {30, 40, 50} Machine M2 contains 2 numbers: {35, 45} Machine M3 contains 5 numbers: {10, 60, 70, 80, 100} Output: {10, 30, 35, 40, 45, 50, 60, 70, 80, 100}
Representation of stream of numbers on each machine is considered as a linked list. A Min Heap can be used to print all numbers in sorted order. Following is the detailed process
- Store the head pointers of the linked lists in a minHeap of size N where N is a number of machines.
- Extract the minimum item from the minHeap. Update the minHeap by replacing the head of the minHeap with the next number from the linked list or by replacing the head of the minHeap with the last number in the minHeap followed by decreasing the size of heap by 1.
- Repeat the above step 2 until heap is not empty. Below is C++ implementation of the above approach.
Implementation:
CPP
// A program to take numbers from different machines and print them in sorted order #include <stdio.h> // A Linked List node struct ListNode { int data; struct ListNode* next; }; // A Min Heap Node struct MinHeapNode { ListNode* head; }; // A Min Heao (Collection of Min Heap nodes) struct MinHeap { int count; int capacity; MinHeapNode* array; }; // A function to create a Min Heap of given capacity MinHeap* createMinHeap( int capacity ) { MinHeap* minHeap = new MinHeap; minHeap->capacity = capacity; minHeap->count = 0; minHeap->array = new MinHeapNode [minHeap->capacity]; return minHeap; } /* A utility function to insert a new node at the beginning of linked list */ void push (ListNode** head_ref, int new_data) { /* allocate node */ ListNode* new_node = new ListNode; /* put in the data */ new_node->data = new_data; /* link the old list off the new node */ new_node->next = (*head_ref); /* move the head to point to the new node */ (*head_ref) = new_node; } // A utility function to swap two min heap nodes. This function // is needed in minHeapify void swap( MinHeapNode* a, MinHeapNode* b ) { MinHeapNode temp = *a; *a = *b; *b = temp; } // The standard minHeapify function. void minHeapify( MinHeap* minHeap, int idx ) { int left, right, smallest; left = 2 * idx + 1; right = 2 * idx + 2; smallest = idx; if ( left < minHeap->count && minHeap->array[left].head->data < minHeap->array[smallest].head->data ) smallest = left; if ( right < minHeap->count && minHeap->array[right].head->data < minHeap->array[smallest].head->data ) smallest = right; if ( smallest != idx ) { swap( &minHeap->array[smallest], &minHeap->array[idx] ); minHeapify( minHeap, smallest ); } } // A utility function to check whether a Min Heap is empty or not int isEmpty( MinHeap* minHeap ) { return (minHeap->count == 0); } // A standard function to build a heap void buildMinHeap( MinHeap* minHeap ) { int i, n; n = minHeap->count - 1; for ( i = (n - 1) / 2; i >= 0; --i ) minHeapify( minHeap, i ); } // This function inserts array elements to heap and then calls // buildHeap for heap property among nodes void populateMinHeap( MinHeap* minHeap, ListNode* *array, int n ) { for ( int i = 0; i < n; ++i ) minHeap->array[ minHeap->count++ ].head = array[i]; buildMinHeap( minHeap ); } // Return minimum element from all linked lists ListNode* extractMin( MinHeap* minHeap ) { if ( isEmpty( minHeap ) ) return NULL; // The root of heap will have minimum value MinHeapNode temp = minHeap->array[0]; // Replace root either with next node of the same list. if ( temp.head->next ) minHeap->array[0].head = temp.head->next; else // If list empty, then reduce heap size { minHeap->array[0] = minHeap->array[ minHeap->count - 1 ]; --minHeap->count; } minHeapify( minHeap, 0 ); return temp.head; } // The main function that takes an array of lists from N machines // and generates the sorted output void externalSort( ListNode *array[], int N ) { // Create a min heap of size equal to number of machines MinHeap* minHeap = createMinHeap( N ); // populate first item from all machines populateMinHeap( minHeap, array, N ); while ( !isEmpty( minHeap ) ) { ListNode* temp = extractMin( minHeap ); printf ( "%d " ,temp->data ); } } // Driver program to test above functions int main() { int N = 3; // Number of machines // an array of pointers storing the head nodes of the linked lists ListNode *array[N]; // Create a Linked List 30->40->50 for first machine array[0] = NULL; push (&array[0], 50); push (&array[0], 40); push (&array[0], 30); // Create a Linked List 35->45 for second machine array[1] = NULL; push (&array[1], 45); push (&array[1], 35); // Create Linked List 10->60->70->80 for third machine array[2] = NULL; push (&array[2], 100); push (&array[2], 80); push (&array[2], 70); push (&array[2], 60); push (&array[2], 10); // Sort all elements externalSort( array, N ); return 0; } |
Python3
# A program to take numbers from different machines and print them in sorted order # A Linked List node class ListNode: def __init__( self , val = 0 , next = None ): self .val = val self . next = next # A Min Heao (Collection of Min Heap nodes) class MinHeap: def __init__( self , capacity): self .count = 0 self .capacity = capacity self .array = [] # A utility function to insert a new node at the beginning of linked list def push(head_ref, new_data): new_node = ListNode(new_data) new_node. next = head_ref head_ref = new_node return head_ref # A utility function to swap two min heap nodes. This function # is needed in minHeapify def swap(a, b): temp = a a = b b = temp return a, b # The standard minHeapify function. def min_heapify(min_heap, idx): left = 2 * idx + 1 right = 2 * idx + 2 smallest = idx if (left < min_heap.count and min_heap.array[left][ 0 ].val < min_heap.array[smallest][ 0 ].val): smallest = left if (right < min_heap.count and min_heap.array[right][ 0 ].val < min_heap.array[smallest][ 0 ].val): smallest = right if smallest ! = idx: min_heap.array[smallest], min_heap.array[idx] = swap( min_heap.array[smallest], min_heap.array[idx]) min_heapify(min_heap, smallest) # A utility function to check whether a Min Heap is empty or not def is_empty(min_heap): return min_heap.count = = 0 # A standard function to build a heap def build_min_heap(min_heap): n = min_heap.count - 1 for i in range ((n - 1 ) / / 2 , - 1 , - 1 ): min_heapify(min_heap, i) # This function inserts array elements to heap and then calls # buildHeap for heap property among nodes def populate_min_heap(min_heap, array, n): for i in range (n): min_heap.array.append((array[i], i)) min_heap.count + = 1 build_min_heap(min_heap) # Return minimum element from all linked lists def extract_min(min_heap): if is_empty(min_heap): return None temp = min_heap.array[ 0 ][ 0 ] if temp. next is not None : min_heap.array[ 0 ] = (temp. next , min_heap.array[ 0 ][ 1 ]) else : min_heap.array[ 0 ] = min_heap.array[min_heap.count - 1 ] min_heap.count - = 1 min_heapify(min_heap, 0 ) return temp # The main function that takes an array of lists from N machines # and generates the sorted output def external_sort(array, n): # Create a min heap of size equal to number of machines min_heap = MinHeap(n) populate_min_heap(min_heap, array, n) while not is_empty(min_heap): temp = extract_min(min_heap) print (temp.val, end = " " ) # Driver program to test above functions if __name__ = = '__main__' : N = 3 # Number of machines array = [ None ] * N # an array of pointers storing the head nodes of the linked lists array[ 0 ] = None array[ 0 ] = push(array[ 0 ], 50 ) array[ 0 ] = push(array[ 0 ], 40 ) array[ 0 ] = push(array[ 0 ], 30 ) # Create a Linked List 35->45 for second machine array[ 1 ] = None array[ 1 ] = push(array[ 1 ], 45 ) array[ 1 ] = push(array[ 1 ], 35 ) # Create Linked List 10->60->70->80 for third machine array[ 2 ] = None array[ 2 ] = push(array[ 2 ], 100 ) array[ 2 ] = push(array[ 2 ], 80 ) array[ 2 ] = push(array[ 2 ], 70 ) array[ 2 ] = push(array[ 2 ], 60 ) array[ 2 ] = push(array[ 2 ], 10 ) external_sort(array, N) |
C#
using System; // define a singly linked list node public class ListNode { // data stored in the node public int data; // reference to the next node in the linked list public ListNode next; } // define a node for the heap, // that holds a reference to a linked list node public class MinHeapNode { // reference to a linked list node public ListNode head; } // define the heap data structure public class MinHeap { // number of nodes in the heap public int count; // maximum number of nodes the heap can hold public int capacity; // an array of MinHeapNode objects, // each containing a linked list node public MinHeapNode[] array; } public class ExternalSort { static MinHeap createMinHeap( int capacity) { MinHeap minHeap = new MinHeap(); minHeap.capacity = capacity; minHeap.count = 0; minHeap.array = new MinHeapNode[minHeap.capacity]; return minHeap; } // define a static method to add a new ListNode object // with specified data value to the beginning of a linked list static void push( ref ListNode head_ref, int new_data) { // create a new ListNode object ListNode new_node = new ListNode(); // set the data value and next reference for the new ListNode object new_node.data = new_data; new_node.next = head_ref; // set the head reference for the linked list to the new ListNode object head_ref = new_node; } static void swap( ref MinHeapNode a, ref MinHeapNode b) { MinHeapNode temp = a; a = b; b = temp; } // define a static method to maintain the min heap property // at a given index in a MinHeap object's array static void minHeapify(MinHeap minHeap, int idx) { int left, right, smallest; left = 2 * idx + 1; right = 2 * idx + 2; smallest = idx; if (left < minHeap.count && minHeap.array[left].head.data < minHeap.array[smallest].head.data) { smallest = left; } if (right < minHeap.count && minHeap.array[right].head.data < minHeap.array[smallest].head.data) { smallest = right; } if (smallest != idx) { swap( ref minHeap.array[smallest], ref minHeap.array[idx]); minHeapify(minHeap, smallest); } } // A utility function to check whether a Min Heap is empty or not static int isEmpty(MinHeap minHeap) { return (minHeap.count == 0) ? 1 : 0; } // A standard function to build a heap static void buildMinHeap(MinHeap minHeap) { int i, n; n = minHeap.count - 1; for (i = (n - 1) / 2; i >= 0; --i) { minHeapify(minHeap, i); } } // This function inserts array elements to heap and then calls // buildHeap for heap property among nodes static void populateMinHeap(MinHeap minHeap, ListNode[] array, int n) { for ( int i = 0; i < n; ++i) { MinHeapNode node = new MinHeapNode(); node.head = array[i]; minHeap.array[minHeap.count++] = node; } buildMinHeap(minHeap); } // Return minimum element from all linked lists static ListNode extractMin(MinHeap minHeap) { if (isEmpty(minHeap) == 1) { return null ; } MinHeapNode temp = minHeap.array[0]; ListNode node = temp.head; if (temp.head.next == null ) { minHeap.array[0] = minHeap.array[minHeap.count - 1]; --minHeap.count; } else { minHeap.array[0].head = temp.head.next; } minHeapify(minHeap, 0); return node; } // The main function that takes an array of lists from N machines // and generates the sorted output static void externalSort(ListNode[] array, int N) { MinHeap minHeap = createMinHeap(N); populateMinHeap(minHeap, array, N); while (isEmpty(minHeap) != 1) { ListNode temp = extractMin(minHeap); Console.Write(temp.data + " " ); } } // Driver function static void Main() { int N = 3; // Number of machines // an array of pointers storing the head nodes of the linked lists ListNode[] array = new ListNode[N]; // Create a Linked List 30->40->50 for first machine array[0] = null ; push( ref array[0], 50); push( ref array[0], 40); push( ref array[0], 30); // Create a Linked List 35->45 for second machine array[1] = null ; push( ref array[1], 45); push( ref array[1], 35); // Create Linked List 10->60->70->80 for third machine array[2] = null ; push( ref array[2], 100); push( ref array[2], 80); push( ref array[2], 70); push( ref array[2], 60); push( ref array[2], 10); // Sort all elements externalSort(array, N); } } // This code is contributed by amit_mangal_ |
Javascript
// A JavaScript program to take numbers from different machines and print them in sorted order // A Linked List node class ListNode { constructor(val = 0, next = null ) { this .val = val; this .next = next; } } // A Min Heap (Collection of Min Heap nodes) class MinHeap { constructor(capacity) { this .count = 0; this .capacity = capacity; this .array = []; } } // A utility function to insert a new node at the beginning of linked list function push(head_ref, new_data) { /* allocate node */ const new_node = new ListNode(new_data); /* link the old list off the new node */ new_node.next = head_ref; /* move the head to point to the new node */ head_ref = new_node; return head_ref; } // A utility function to swap two min heap nodes. This function // is needed in minHeapify function swap(a, b) { const temp = a; a = b; b = temp; return [a, b]; } // The standard minHeapify function. function min_heapify(min_heap, idx) { const left = 2 * idx + 1; const right = 2 * idx + 2; let smallest = idx; if ( left < min_heap.count && min_heap.array[left][0].val < min_heap.array[smallest][0].val ) { smallest = left; } if ( right < min_heap.count && min_heap.array[right][0].val < min_heap.array[smallest][0].val ) { smallest = right; } if (smallest !== idx) { [min_heap.array[smallest], min_heap.array[idx]] = swap( min_heap.array[smallest], min_heap.array[idx] ); min_heapify(min_heap, smallest); } } // A utility function to check whether a Min Heap is empty or not function is_empty(min_heap) { return min_heap.count === 0; } // A standard function to build a heap function build_min_heap(min_heap) { const n = min_heap.count - 1; for (let i = Math.floor((n - 1) / 2); i >= 0; i--) { min_heapify(min_heap, i); } } // This function inserts array elements to heap and then calls // buildHeap for heap property among nodes function populate_min_heap(min_heap, array, n) { for (let i = 0; i < n; i++) { min_heap.array.push([array[i], i]); min_heap.count += 1; } build_min_heap(min_heap); } // Return minimum element from all linked lists function extract_min(min_heap) { if (is_empty(min_heap)) { return null ; } const temp = min_heap.array[0][0]; if (temp.next !== null ) { min_heap.array[0] = [temp.next, min_heap.array[0][1]]; } else { min_heap.array[0] = min_heap.array[min_heap.count - 1]; min_heap.count -= 1; } min_heapify(min_heap, 0); return temp; } // The main function that takes an array of lists from N machines // and generates the sorted output function external_sort(array, n) { // Create a min heap of size equal to number of machines const min_heap = new MinHeap(n); populate_min_heap(min_heap, array, n); let sortedList = '' ; while (!is_empty(min_heap)) { const temp = extract_min(min_heap); sortedList += `${temp.val} `; } console.log(sortedList.trim()); } // Driver program to test above functions const N = 3; // Number of machines const array = new Array(N); // an array of pointers storing the head nodes of the linked lists array[0] = null ; array[0] = push(array[0], 50); array[0] = push(array[0], 40); array[0] = push(array[0], 30); // Create a Linked List 35->45 for second machine array[1] = null ; array[1] = push(array[1], 45); array[1] = push(array[1], 35); // Create Linked List 10->60->70->80 for third machine array[2] = null ; array[2] = push(array[2], 100); array[2] = push(array[2], 80); array[2] = push(array[2], 70); array[2] = push(array[2], 60); array[2] = push(array[2], 10); external_sort(array, N); |
10 30 35 40 45 50 60 70 80 100
Time complexity: O(N) for min heap
Auxiliary Space: O(N)
Approach : Using DP
This code uses a priority queue (min heap) to efficiently merge the sorted lists from different machines. The mergeLists function takes a vector of linked lists and merges them into a single sorted linked list using a min heap. The externalSort function converts the array of linked lists into a vector and then calls mergeLists to obtain the sorted list, which is then printed.
Note that this implementation assumes ascending order sorting. If you want to sort in descending order, you can modify the CompareNode struct and change the comparison operator in the operator() function accordingly.
C++
#include <iostream> #include <vector> #include <queue> using namespace std; struct ListNode { int data; ListNode* next; }; struct CompareNode { bool operator()( const ListNode* a, const ListNode* b) { return a->data > b->data; } }; ListNode* createNode( int data) { ListNode* newNode = new ListNode; newNode->data = data; newNode->next = nullptr; return newNode; } void push(ListNode** head, int data) { if (*head == nullptr) { *head = createNode(data); } else { ListNode* newNode = createNode(data); newNode->next = *head; *head = newNode; } } void printList(ListNode* head) { while (head != nullptr) { cout << head->data << " " ; head = head->next; } } ListNode* mergeLists(vector<ListNode*>& lists) { ListNode* dummy = createNode(0); ListNode* tail = dummy; priority_queue<ListNode*, vector<ListNode*>, CompareNode> minHeap; for (ListNode* list : lists) { if (list != nullptr) { minHeap.push(list); } } while (!minHeap.empty()) { ListNode* node = minHeap.top(); minHeap.pop(); tail->next = node; tail = tail->next; if (node->next != nullptr) { minHeap.push(node->next); } } return dummy->next; } void externalSort(ListNode* array[], int N) { vector<ListNode*> lists(array, array + N); ListNode* sortedList = mergeLists(lists); printList(sortedList); } int main() { int N = 3; // Number of machines ListNode* array[N]; array[0] = nullptr; push(&array[0], 50); push(&array[0], 40); push(&array[0], 30); array[1] = nullptr; push(&array[1], 45); push(&array[1], 35); array[2] = nullptr; push(&array[2], 100); push(&array[2], 80); push(&array[2], 70); push(&array[2], 60); push(&array[2], 10); externalSort(array, N); return 0; } |
Output:
10 30 35 40 45 50 60 70 80 100
space complexity: O(N + K)
time complexity: O(N + K log N)
Please Login to comment...