Reputation: 1656
Let's say I have an array A = <1,6,2,7,3,8,4,9,5> pseudocode for Heapsort:
BUILD-MAX-HEAP(A)
n = A.heapsize = A.length
for i = floor(n/2) down to 1
MAX-HEAPIFY(A,i)
MAX-HEAPIFY(A,i)
n = A.heap-size
l = LEFT(i)
r = RIGHT(i)
if l <= n and A[l] > A[i]
largest = l
if r <= n and A[r] > A[largest]
largest = r
if largest != i
exchange A[i] <-> A[largest]
MAX-HEAPIFY(A,largest)
I know BUILD-MAX-HEAP will first call MAX-HEAPIFY(A,4), which will exchange 7 and 9, then after MAX-HEAPIFY (A,3) it will switch 8 and 2. Then it will call MAX-HEAPIFY(A,2), and this is where I get confused. This is how the heap looks when MAX-HEAPIFY(A,2) is called
The first thing that will happen is that 6 and 7 will be exchanged, then it will call MAX-HEAPIFY(A,4) (because 4 is now largest), and exchange 6 and 9, then it will call MAX-HEAPIFY(A,8) but nothing will happen because you've reached a leaf, so then it returns to the function that called it.
MAX-HEAPIFY(A-8) was called by MAX-HEAPIFY(A,4) so it returns to it
MAX-HEAPIFY(A,4) was called by MAX-HEAPIFY(A,2) so it returns to it
but now A[2] < A[4] (because 7 < 9), and it is at this point that I wonder how it knows to call MAX-HEAPIFY(A,2) again to exchange 7 and 9. When a recursive function (or subroutine) returns to the one that called it, there is no more code to be executed (since MAX-HEAPIFY only calls MAX-HEAPIFY at the end of the function), so it will return back up the recursion stack and in my mind it feels like 7 will still be the parent of 9
Sorry if this is confusing, but can somebody walk me through this to help me understand how exactly this is recursively max-heapifying itself?
Upvotes: 2
Views: 4208
Reputation: 29730
The following is the series of steps I get when following your algorithm (note the levels of indent when we recurse at the end of each). Every time we exit the function, we just return to the main program (calling max_heapify
with the numbers 4 down to 1). I'm not positive where your interpretation is off, but I'm hoping the following makes it clearer.
for i in (4,3,2,1):
MAX-HEAPIFY(A,i)
MAX-HEAPIFY(A,4):
largest=4 # initialized
l=8
r=9
largest=8 # calculated
swap A[4] and a[8]:
A = <1,6,2,9,3,8,4,7,5>
MAX-HEAPIFY(A, 8):
largest=8 # initialized
l=16
r=17
...return
...return
MAX-HEAPIFY(A,3):
largest=3 # initialized
l=6
r=7
largest=6 # calculated
swap A[3] and A[6]:
A = <1,6,8,9,3,2,4,7,5>
MAX-HEAPIFY(A, 6):
largest=6
l=12
r=13
...return
...return
MAX-HEAPIFY(A,2):
largest=2 # initialized
l=4
r=5
largest=4 # calculated
swap A[2]and A[4]:
A = <1,9,8,6,3,2,4,7,5>
MAX-HEAPIFY(A, 4):
largest=4 # initialized
l=8
r=9
largest=8
swap A[4] and A[8]:
A = <1,9,8,7,3,2,4,6,5>
MAX-HEAPIFY(A, 8):
largest=8 # initialized
l=16
r=17
...return
...return
...return
MAX-HEAPIFY(A,1):
largest=1 # initialized
l=2
r=3
largest=2 # calculated
swap A[1] and A[2]:
A = <9,1,8,7,3,2,4,6,5>
MAX-HEAPIFY(A, 2):
largest=2: # initialized
l=4
r=5
largest=4: # calculated
swap A[2] and A[4]:
A = <9,7,8,1,3,2,4,6,5>
MAX-HEAPIFY(A, 4):
largest=4: # initialized
l=8
r=9
largest=8: # calculated
swap A[4] and A[8]:
A = <9,7,8,6,3,2,4,1,5>
MAX-HEAPIFY(A, 8):
largest=8: # initialized
l=16
r=17
...return
...return
...return
...return
Done!
A = <9,7,8,6,3,2,4,1,5>
I then went so far as to translate your algorithm (almost directly) into python (note I had to make a few tweaks for python's 0-based index):
def build_max_heap(A):
for i in range(len(A)//2, 0, -1):
max_heapify(A, i)
def left(x):
return 2 * x
def right(x):
return 2 * x + 1
def max_heapify(A, i):
n = len(A)
largest = i
l = left(i)
r = right(i)
if l<=n and A[l-1] > A[i-1]:
largest = l
if r <=n and A[r-1] > A[largest-1]:
largest = r
if largest !=i:
A[i-1], A[largest-1] = A[largest-1], A[i-1]
max_heapify(A,largest)
if __name__ == '__main__':
A = [1,6,2,7,3,8,4,9,5]
build_max_heap(A) # modifies in-place
print(A)
This prints: [9, 7, 8, 6, 3, 2, 4, 1, 5] (which agrees with our manual iterations)
...and for one more check, using python's heapq
module with its private method _heapify_max
:
import heapq
A = [1,6,2,7,3,8,4,9,5]
heapq._heapify_max(A)
print(A)
...prints the same: [9, 7, 8, 6, 3, 2, 4, 1, 5]
Upvotes: 1