#include <bits/stdc++.h> // Includes common standard libraries (iostream, algorithm for swap)
using namespace std; // Use the standard namespace
// Function to perform heapify operation for a Max Heap.
// It ensures that the subtree rooted at 'i' satisfies the Max Heap property.
// 'arr': The array representing the heap. (Assumes 1-based indexing)
// 'n': The current logical size of the heap (number of valid elements).
// 'i': The index of the root of the subtree to heapify.
// Time Complexity: O(log N)
// Space Complexity: O(log N) for recursion stack.
void heapify(int arr[], int n, int i) {
int largest = i; // Assume current node 'i' is the largest.
int left = 2 * i; // Index of left child (1-based).
int right = 2 * i + 1; // Index of right child (1-based).
// Check if left child exists within bounds and is greater than current 'largest'.
if(left <= n && arr[largest] < arr[left]) {
largest = left; // If so, left child is the new candidate for largest.
// Check if right child exists within bounds and is greater than current 'largest'.
// (Note: 'largest' might now be 'left' if left child was larger).
if(right <= n && arr[largest] < arr[right]) {
largest = right; // If so, right child is the new candidate for largest.
// If 'largest' is not the original 'i', it means a child was larger.
swap(arr[i], arr[largest]); // Swap current node with the largest child.
heapify(arr, n, largest); // Recursively call heapify on the affected subtree
// to ensure property is maintained downwards.
// Function to perform Heap Sort on an array.
// 'arr': The array to be sorted (assumes 1-based indexing for heap operations).
// 'size': The number of elements in the array.
// Time Complexity: O(N log N) (O(N) for build heap + O(N log N) for sorting phase)
// Space Complexity: O(1) auxiliary space (in-place sort).
void heapSort(int arr[], int size) {
// Phase 2: Sorting (Extract Max and Heapify)
// Loop until only one element is left in the heap (which will be sorted).
// Step 1: Swap the root (largest element) with the last element of the current heap.
// Step 2: Decrease the effective size of the heap.
// The swapped element at arr[size] is now in its sorted position.
// Step 3: Heapify the new root (arr[1]) to restore the Max Heap property.
// This brings the next largest element to the root.
// Example array to be sorted. arr[0] is unused as per 1-based indexing.
int arr[6] = {-1, 54, 53, 55, 50, 52};
int size = 5; // Number of actual elements to be sorted.
// Phase 1: Build a Max Heap from the initial array.
// Call heapify for all non-leaf nodes in reverse order (from size/2 down to 1).
// This phase takes O(N) time.
for(int i = size / 2; i > 0; i--) {
// Print the array after heap creation (it's now a Max Heap, not sorted yet).
cout << "UnSorted array (after Max Heap creation) : ";
for(int i = 1; i <= size; i++) {
cout << endl; // Expected: e.g., 55 54 53 50 52 (a valid Max Heap)
// Call heapSort to sort the heapified array.
// Print the sorted array.
cout << "Sorted array (Heap Sort) : ";
for(int i = 1; i <= size; i++) {
cout << endl; // Expected: 50 52 53 54 55 (ascending order)
Example Array: {-1, 54, 53, 55, 50, 52}
Initial: [?, 54, 53, 55, 50, 52]
heapify(arr, 5, 2): Children 50 (at 4), 52 (at 5). 53 is largest. No change.
Array: [?, 54, 53, 55, 50, 52]
heapify(arr, 5, 1): Children 53 (at 2), 55 (at 3). Largest is 55.
Swap arr[1] (54) and arr[3] (55). Array: [?, 55, 53, 54, 50, 52]
Recursively heapify(arr, 5, 3) (on new position of 54)
Node at 3 is 54. Children 50 (at 4), 52 (at 5). Largest among 54, 50, 52 is 54. No change.
Heap built. Max Heap: [?, 55, 53, 54, 50, 52] (or similar permutation where root is max)
Swap arr[1] (55) with arr[5] (52). Array: [?, 52, 53, 54, 50, 55]
heapify(arr, 4, 1) (on new root 52):
Node 52, children 53, 54. Largest is 54.
Swap 52 and 54. Array: [?, 54, 53, 52, 50, 55]
Recursively heapify(arr, 4, 3) (on new position of 52)
Node 52, child 50. Largest is 52. No change.
Heap (current): [?, 54, 53, 52, 50], Sorted part: [55]
Swap arr[1] (54) with arr[4] (50). Array: [?, 50, 53, 52, 54, 55]
heapify(arr, 3, 1) (on new root 50):
Node 50, children 53, 52. Largest is 53.
Swap 50 and 53. Array: [?, 53, 50, 52, 54, 55]
Recursively heapify(arr, 3, 2) (on new position of 50)
Node 50, child 52. Largest is 52.
Swap 50 and 52. Array: [?, 53, 52, 50, 54, 55]
Recursively heapify(arr, 3, 3) (on new position of 50)
Node 50, no children in bounds. No change.
Heap (current): [?, 53, 52, 50], Sorted part: [54, 55]
Swap arr[1] (53) with arr[3] (50). Array: [?, 50, 52, 53, 54, 55]
heapify(arr, 2, 1) (on new root 50):
Node 50, child 52. Largest is 52.
Swap 50 and 52. Array: [?, 52, 50, 53, 54, 55]
Recursively heapify(arr, 2, 2) (on new position of 50)
Node 50, no children in bounds. No change.
Heap (current): [?, 52, 50], Sorted part: [53, 54, 55]
Swap arr[1] (52) with arr[2] (50). Array: [?, 50, 52, 53, 54, 55]
heapify(arr, 1, 1) (on new root 50):
Node 50, no children in bounds. No change.
Loop terminates as size is now 1.
Final Sorted Array: [?, 50, 52, 53, 54, 55] (ignoring arr[0])