2IL50 Data Structures: 2018-19 Q3 Lecture 3: Heaps
2IL50 Data Structures: 2018-19 Q3 Lecture 3: Heaps
2018-19 Q3
Lecture 3: Heaps
Solving recurrences
Alternatively: Guess the solution and use the substitution method to prove
that your guess it is correct.
How to guess:
1. expand the recursion
2. draw a recursion tree
Example
Example(A)
► A is an array of length n
1. n = A.length
2. if n==1
3. then return A[1]
4. else begin
5. Copy A[1…⌈n/2⌉] to auxiliary array B[1...⌈n/2⌉]
6. Copy A[1…⌈n/2⌉] to auxiliary array C[1…⌈n/2⌉]
7. b = Example(B); c = Example(C)
8. for i = 1 to n
9. do for j = 1 to i
10. do A[i] = A[j]
11. return 43
12. end
Example
Example(A) Let T(n) be the worst case running time of Example
on an array of length n.
► A is an array of length n
1. n = A.length Lines 1,2,3,4,11, and 12 take Θ(1) time.
2. if n==1 Lines 5 and 6 take Θ(n) time.
Line 7 takes Θ(1) + 2 T(⌈n/2⌉) time.
3. then return A[1] Lines 8 until 10 take
4. else begin n i n
5.
Copy A[1…⌈n/2⌉] to auxiliary array B[1...
i1 ⌈
jn/2
1
Θ(1)
⌉] i1
Θ(i) Θ(n 2 )
time.
Then we have:
1. If f(n) = O(nlog a – ε) for some constant ε > 0, then T(n) = Θ(nlog a). b
b
3. If f(n) = Ω(nlog a + ε) for some constant ε > 0, and if af(n/b) ≤ cf(n) for
b
some constant c < 1 and all sufficiently large n, then T(n) = Θ(f(n))
Quiz
Recurrence Master theorem?
Proof: by induction on n
Proof: by induction on n
Inductive step:
IH: Assume that for all 1 ≤ k < n it holds that T(k) ≤ ck2.
Then T(n) = 7T(⌊n/3⌋) + n2
≤ 7 ⋅ c ⋅ (⌊n/3⌋)2 + n2 (by IH)
≤ 7/9 ⋅ cn2 + n2
= cn2 – 2/9 ⋅ cn2 + n2
≤ cn2 (if – 2/9 ⋅ cn2 + n2 ≤ 0)
(for c ≥ 9/2)
Substitution
1 if n = 1 or n = 2
T(n) =
7T(⌊n/3⌋) + n2 if n > 2
Proof: by induction on n
Inductive step:
[…]
i
i1
½ n(n+1) = Θ(n2)
n
i
i1
2
⅙ n(n+1)(2n+1) = Θ(n3)
Heaps
Event-driven simulation
Stores a set of events, processes first event (highest priority)
Operations
Insert(S, x): inserts element x into S, that is, S ← S ⋃ {x}
Maximum(S): returns the element of S with the largest key
Extract-Max(S): removes and returns the element of S with the
largest key
Increase-Key(S, x, k): give key[x] the value k
condition: k is larger than the current value of key[x]
Min-priority queue …
Implementing a priority queue
L.head / 6 2 7 9 /
Operations
Search(L, key)
O(n)
Insert(L, x)
O(1)
Delete(L, x)
O(1)
Implementing a priority queue
Today
30 19
30 8 11 12
17 2 5
Heap
nearly complete binary tree, filled on all levels except possibly the lowest.
(lowest level is filled from left to right)
30 19
30 19
30 8 21
30 8 11 12 35
30 19
17 2 5
30 8 12
Heap
nearly complete binary tree, filled on all levels except possibly the lowest.
(lowest level is filled from left to right)
Proof:
Properties of a max-heap
Lemma
The largest element in a max-heap is stored at the root.
Proof: x root
y arbitrary node
x
z1, z2, …, zk nodes on path z1
between x and y
z2
30 19
30 8 11 12
17 2 5
Implementing a heap with an array
35
30 19
30 8 11 12
35 30 19 30 8 11 12 17 2 5
1 2 3 4
heap-size[A]
level 1
level 2, position 3
1 2 3 4
heap-size[A]
kth node on level j is stored at position A[2j+k-1]
left child of node at position i = Left(i) = 2i
right child of node at position i = Right(i) = 2i + 1
parent of node at position i = Parent(i) = ⌊ i/2 ⌋
Priority queue
Max-priority queue
abstract data type (ADT) that stores a set S of elements, each with an
associated key (integer value).
Operations
Insert(S, x): inserts element x into S, that is, S ← S ⋃ {x}
Maximum(S): returns the element of S with the largest key
Extract-Max(S): removes and returns the element of S with the
largest key
Increase-Key(S, x, k): give key[x] the value k
condition: k is larger than the current value of key[x]
Implementing a max-priority queue
Set S is stored as a heap in an array A.
Operations: Maximum, Extract-Max, Insert, Increase-Key.
35 30 19 30 8 11 12 17 2 5
1 2 3 4
heap-size[A]
Implementing a max-priority queue
Set S is stored as a heap in an array A.
Operations: Maximum, Extract-Max, Insert, Increase-Key.
35 30 19 30 8 11 12 17 2 5
1 2 3 4
heap-size[A]
Maximum(A)
1. if heap-size[A] < 1
2. then error
3. else return A[1]
35 30 19 30 8 11 12 17 2 5
1 2 3 4
heap-size[A]
Implementing a max-priority queue
Set S is stored as a heap in an array A.
Operations: Maximum, Extract-Max, Insert, Increase-Key.
35
30
30 19
30
17 8 11 12
17 2 5
Implementing a max-priority queue
Set S is stored as a heap in an array A.
Operations: Maximum, Extract-Max, Insert, Increase-Key.
35
5
30 19
Heap-Extract-Max(A)
1. if heap-size[A] < 1 30 8 11 12
2. then error
3. max = A[1] 17 2 5
4. A[1] = A [heap-size[A]] restore heap property
5. heap-size[A] = heap-size[A]–1
6. Max-Heapify(A,1)
7. return max
Max-Heapify
Max-Heapify(A, i)
► ensures that the heap whose root is stored at position i has the max-heap
property
► assumes that the binary subtrees rooted at Left(i) and Right(i) are max-
heaps
Max-Heapify
Max-Heapify(A, i)
► ensures that the heap whose root is stored at position i has the max-heap
property
► assumes that the binary subtrees rooted at Left(i) and Right(i) are max-
heaps
Max-Heapify(A,1) 10
40
exchange A[1] with largest child
40
10
35 19
Max-Heapify(A,2)
30 10
35 11 12
exchange A[2] with largest child
Max-Heapify(A,5) 17 2 5
35
30 19
Increase-Key(A, i, key) 30 8 11
42 12
1. if key < A[i]
2. then error 17 2 5
3. A[i] = key
4. while i>1 and A[Parent(i)] < A[i]
5. do exchange A[Parent(i)] and A[i]
6. i = Parent(i)
Loop Invariant
P(i): nodes i+1, …, n are each the root of a max-heap
Maintenance
P(i) holds before line 3 is executed,
P(i – 1) holds afterwards
Building a heap
Build-Max-Heap(A)
1. heap-size = A.length
2. for i = A.length downto 1
3. do Max-Heapify(A,i) O(height of node i)
h=1
h=0
The sorting problem
Input: a sequence of n numbers ‹a1, a2, …, an›
Output: a permutation of the input such that ‹ai1 ≤ … ≤ ain›
Loop invariant
P(i): A[i+1 ... n] is sorted and contains the n – i largest elements,
A[1…i] is a max-heap on the remaining elements
Maintenance
P(i) holds before lines 3-5 are executed,
P(i – 1) holds afterwards