1

 Heapsort
 Priority Queues
 Quicksort

2

 A heap is a “complete” binary tree, usually represented as an array:

3

 To represent a heap as an array:
 Parent(i) { return ëi/2û; }
 Left(i) { return 2*i; }
 right(i) { return 2*i + 1; }

4

 Heaps also satisfy the heap property:
 A[Parent(i)] ³ A[i] for
all nodes i > 1
 In other words, the value of a node is at most the value of its parent
 The largest value is thus stored at the root (A[1])
 Because the heap is a binary tree, the height of any node is at most Q(lg n)

5

 Heapify(): maintain the heap property
 Given: a node i in the heap with children l and r
 Given: two subtrees rooted at l and r, assumed to be heaps
 Action: let the value of the parent node “float down” so subtree at i
satisfies the heap property
 If A[i] < A[l] or A[i] < A[r], swap A[i] with the largest of
A[l] and A[r]
 Recurse on that subtree
 Running time: O(h), h = height of heap = O(lg n)

6

 We can build a heap in a bottomup manner by running Heapify() on
successive subarrays
 Fact: for array of length n, all elements in range
A[ën/2û + 1 .. n] are heaps (Why?)
 So:
 Walk backwards through the array from n/2 to 1, calling Heapify() on
each node.
 Order of processing guarantees that the children of node i are heaps
when i is processed

7

 // given an unsorted array A, make A a heap
 BuildHeap(A)
 {
 heap_size(A) = length(A);
 for (i = ëlength[A]/2û downto 1)
 Heapify(A, i);
 }

8

 Each call to Heapify() takes O(lg n) time
 There are O(n) such calls (specifically, ën/2û)
 Thus the running time is O(n lg n)
 Is this a correct asymptotic upper bound?
 Is this an asymptotically tight bound?
 A tighter bound is O(n)
 How can this be? Is there a flaw
in the above reasoning?

9

 To Heapify() a subtree takes O(h) time where h is the height of the
subtree
 h = O(lg m), m = # nodes in subtree
 The height of most subtrees is small
 Fact: an nelement heap has at most én/2^{h}^{+1}ù nodes of height h
 CLR 7.3 uses this fact to prove that BuildHeap() takes O(n) time

10

 Given BuildHeap(), an inplace
sorting algorithm is easily constructed:
 Maximum element is at A[1]
 Discard by swapping with element at A[n]
 Decrement heap_size[A]
 A[n] now contains correct value
 Restore heap property at A[1] by calling Heapify()
 Repeat, always swapping A[1] for A[heap_size(A)]

11

 Heapsort(A)
 {
 BuildHeap(A);
 for (i = length(A) downto 2)
 {
 Swap(A[1], A[i]);
 heap_size(A) = 1;
 Heapify(A, 1);
 }
 }

12

 The call to BuildHeap() takes O(n) time
 Each of the n  1 calls to Heapify() takes O(lg n) time
 Thus the total time taken by HeapSort()
= O(n) + (n  1) O(lg n)
= O(n) + O(n lg n)
= O(n lg n)

13

 Heapsort is a nice algorithm, but in practice Quicksort (coming up)
usually wins
 But the heap data structure is incredibly useful for implementing priority
queues
 A data structure for maintaining a set S of elements, each with an
associated value or key
 Supports the operations Insert(), Maximum(), and ExtractMax()
 What might a priority queue be useful for?

14

 Insert(S, x) inserts the element x into set S
 Maximum(S) returns the element of S with the maximum key
 ExtractMax(S) removes and returns the element of S with the maximum key
 How could we implement these operations using a heap?

15

 And now, a realworld example…

16

 And now, a realworld example…combat billiards
 Sort of like pool...
 Except you’re trying to
kill the other players…
 And the table is the size
of a polo field…
 And the balls are the
size of Suburbans...
 And instead of a cue
you drive a vehicle
with a ram on it
 Problem: how do you simulate the physics?

17

 Simplifying assumptions:
 Grated version: No players
 Just n balls bouncing around
 No spin, no friction
 Easy to calculate the positions of the balls at time T_{n} from
time T_{n1} if there are no collisions in between
 Simple elastic collisions

18

 Assume we know how to compute when two moving spheres will intersect
 Given the state of the system, we can calculate when the next collision
will occur for each ball
 At each collision C_{i}:
 Advance the system to the time T_{i} of the collision
 Recompute the next collision for the ball(s) involved
 Find the next overall collision C_{i}_{+1} and repeat
 How should we keep track of all these collisions and when they occur?

19

 HeapInsert(A, key) // what’s
running time?
 {
 heap_size[A] ++;
 i = heap_size[A];
 while (i > 1 AND
A[Parent(i)] < key)
 {
 A[i] = A[Parent(i)];
 i = Parent(i);
 }
 A[i] = key;
 }

20

 HeapMaximum(A)
 {
 // This one is really tricky:
 return A[i];
 }

21

 HeapExtractMax(A)
 {
 if (heap_size[A] < 1) {
error; }
 max = A[1];
 A[1] = A[heap_size[A]]
 heap_size[A] ;
 Heapify(A, 1);
 return max;
 }

22

 Extract the next collision C_{i} from the queue
 Advance the system to the time T_{i} of the collision
 Recompute the next collision(s) for the ball(s) involved
 Insert collision(s) into the queue, using the time of occurrence as the
key
 Find the next overall collision C_{i}_{+1} and repeat

23

 More natural to use Minimum() and ExtractMin()
 What if a player hits a ball?
 Need to code up a Delete() operation
 How? What will the running time
be?

24

 Sorts in place
 Sorts O(n lg n) in the average case
 Sorts O(n^{2}) in the worst case
 So why would people use it instead of merge sort?
