From 83e54834d8a73b7608fa6ce740f3b52977b79c2d Mon Sep 17 00:00:00 2001 From: Jidong Xiao Date: Tue, 22 Apr 2025 19:34:31 -0400 Subject: [PATCH] min heap, still need to reverse --- lectures/24_priority_queues_II/README.md | 20 +++++++---- lectures/24_priority_queues_II/heap_sort.cpp | 35 +++++++++++--------- 2 files changed, 33 insertions(+), 22 deletions(-) diff --git a/lectures/24_priority_queues_II/README.md b/lectures/24_priority_queues_II/README.md index f13ac0e..bcc4fdf 100644 --- a/lectures/24_priority_queues_II/README.md +++ b/lectures/24_priority_queues_II/README.md @@ -116,6 +116,10 @@ organized heap data, but incur a O(n log n) cost. Why? - The following is the sort algorithm with a main function to test it; the code makes a min heap. ```cpp +#include +#include +#include + /* The heapify function is designed to ensure that a subtree rooted at a given index i * in an array representation of a min heap maintains the heap property. * @@ -160,14 +164,18 @@ std::vector sortArray(std::vector& nums) { heapify(nums, n, i); } - // now the first one is the largest, swap it to the back + // now the first one is the smallest, swap it to the back // do this n-1 times. - for(int i=0; i<(n-1); i++){ + for(int i=n-1; i>0; i--){ // build the min heap again, with 0 being the root. - // but only consider n-1-i elements, as the others are already in the right place. - heapify(nums, n-1-i, 0); + // but only consider i elements, as the others are already in the right place. + std::swap(nums[0], nums[i]); // move smallest to the end + heapify(nums, i, 0); } + // reverse to get ascending order + std::reverse(nums.begin(), nums.end()); + return nums; } @@ -203,10 +211,10 @@ The above program prints the following: $ g++ heap_sort.cpp $ ./a.out Original array: -42 12 13 65 98 45 97 85 76 90 +42 12 13 65 98 45 97 85 76 90 Sorted array: -12 42 13 65 90 45 97 85 76 98 +12 13 42 45 65 76 85 90 97 98 ``` ## 24.9 Summary Notes about Vector-Based Priority Queues diff --git a/lectures/24_priority_queues_II/heap_sort.cpp b/lectures/24_priority_queues_II/heap_sort.cpp index 0a0b325..90384b3 100644 --- a/lectures/24_priority_queues_II/heap_sort.cpp +++ b/lectures/24_priority_queues_II/heap_sort.cpp @@ -1,8 +1,9 @@ #include #include +#include /* The heapify function is designed to ensure that a subtree rooted at a given index i - * in an array representation of a heap maintains the heap property. + * in an array representation of a min heap maintains the heap property. * While the function doesn't have an explicit base case like some recursive functions, * it inherently terminates due to the following conditions: * @@ -11,19 +12,19 @@ * In this scenario, the conditions left < n and right < n in the if statements evaluating the children will both be false, * preventing further recursive calls. * - * Heap Property Satisfaction: If the node at index i is greater than or equal to its children (or if it has no children), - * the heap property is already satisfied. Consequently, the variable largest remains equal to i, - * and the condition largest != i evaluates to false. + * Heap Property Satisfaction: If the node at index i is less than or equal to its children (or if it has no children), + * the heap property is already satisfied. Consequently, the variable smallest remains equal to i, + * and the condition smallest != i evaluates to false. * This prevents the swap operation and the subsequent recursive call, leading to termination. * In essence, the function will return when: * The node is a leaf node. - * The node's value is greater than or equal to its children's values, maintaining the heap property. + * The node's value is less than or equal to its children's values, maintaining the heap property. * These implicit conditions ensure that the recursion does not continue indefinitely. * * Why Not Just Heapify Once? A single call to heapify on the entire array * wouldn't suffice because heapify is designed to correct violations of * the heap property starting from a specific node, assuming its subtrees are already heaps. - * Initially, the array doesn't have this structure, so multiple calls are necessary to build the initial max-heap. + * Initially, the array doesn't have this structure, so multiple calls are necessary to build the initial min-heap. * Similarly, during the sorting phase, each extraction disrupts the heap structure, necessitating a call to heapify to restore order. * */ @@ -40,8 +41,8 @@ void heapify(std::vector& nums, int n, int i){ smallest = right; } - // after the above, smallest basically will either stay the same, or will be either left or right, depending on nums[left] is larger or nums[right] is larger. largest stays the same if it is already larger than its two children. - // if largest is changed, then we do need to swap. + // after the above, smallest basically will either stay the same, or will be either left or right, depending on nums[left] is smaller or nums[right] is smaller. smallest stays the same if it is already smallest than its two children. + // if smallest is changed, then we do need to swap. if(smallest != i){ std::swap(nums[i], nums[smallest]); heapify(nums, n, smallest); @@ -58,20 +59,22 @@ std::vector sortArray(std::vector& nums) { // This bottom-up approach guarantees that each subtree satisfies the heap property before moving to the next node. for(int i=n/2-1; i>=0; i--){ // heapify the subtree whose root is at i - // i.e., build a max heap, with i being the root; and this heap contains nodes from i to n-1; + // i.e., build a min heap, with i being the root; and this heap contains nodes from i to n-1; heapify(nums, n, i); } - // now the first one is the largest, swap it to the back + // now the first one is the smallest, swap it to the back // do this n-1 times. - for(int i=0; i<(n-1); i++){ - // nums[0] is always the largest one - std::swap(nums[0], nums[n-1-i]); - // build the max heap again, with 0 being the root. - // but only consider n-1-i elements, as the others are already in the right place. - heapify(nums, n-1-i, 0); + for(int i=n-1; i>0; i--){ + // build the min heap again, with 0 being the root. + // but only consider i elements, as the others are already in the right place. + std::swap(nums[0], nums[i]); // move smallest to the end + heapify(nums, i, 0); } + // reverse to get ascending order + std::reverse(nums.begin(), nums.end()); + return nums; }