




Study with the several resources on Docsity
Earn points by helping other students or get them with a premium plan
Prepare for your exams
Study with the several resources on Docsity
Earn points to download
Earn points by helping other students or get them with a premium plan
Community
Ask the community for help and clear up your study doubts
Discover the best universities in your country according to Docsity users
Free resources
Download our free guides on studying techniques, anxiety management strategies, and thesis advice from Docsity tutors
The importance of algorithm correctness and provides an example of using loop invariants to prove the correctness of an algorithm for finding the middle of a linked list. The document also introduces the concept of heap data structures and their use in maintaining the heap property. The document may be useful for university students studying computer science, specifically algorithms and data structures.
Typology: Study notes
1 / 8
This page cannot be seen from the preview
Don't miss anything!
Jared Saia
University of New Mexico
Ancient Puzzles
Loop Invariants
Binary Heaps
The most important aspect of algorithms is their correctness
An algorithm by definition
always
gives the right answer to
the problem
heuristicA procedure which doesn’t always give the right answer is a
All things being equal, we prefer an algorithm to a heuristic
How do we prove an algorithm is really correct?
A useful tool for proving correctness is loop invariants.
Three
things must be shown about a loop invariant
Initialization:
Invariant is true before first iteration of loop
Maintenance:
If invariant is true before iteration
i , it is also
true before iteration
i (^) + 1 (for any
i )
Termination:
When the loop terminates, the invariant gives
a property which can be used to show the algorithm is correct
the following interview question:We’ll prove the correctness of a simple algorithm which solves
list onceFind the middle of a linked list, while only going through the
the pointers moves twice as fast as the otherThe basic idea is to keep two pointers into the list, one of
the ((Call the head of the list the 0-th elem, and the tail of the list
n (^) −
(^) 1)-st element, assume that
n (^) −
(^) 1 is an even number)
GetMiddle (List l){
while ((pFast->next)&&(pFast->next->next)){pSlow = pFast = l;
pSlow = pSlow->nextpFast = pFast->next->next
return pSlow}
Invariant: At the start of the
i -th iteration of the while loop,
pSlow points to the
i -th element in the list and pFast points
to the
i -th element
Initialization:
True when
i
= 0 since both pointers are at
the head
Maintenance:
if pSlow, pFast are at positions
i
and 2
i
re-
spectively before
i -th iteration, they will be at positions
i (^) + 1,
i (^) + 1) respectively before the
i (^) + 1-st iteration
Termination:
When the loop terminates, pFast is at ele-
ment
n (^) −
(^) 1. Then by the loop invariant, pSlow is at element
n
−
(^) 1)
a loop in a linked listFigure out how to use a similar idea to determine if there is
without marking nodes!
For every node
i
other than the root, A[Parent (i)]
A[i]
For every node
i
other than the root, A[Parent (i)]
A[i]
Parent is always at least as large as its children
Largest element is at the root
(A Min-heap is organized the opposite way)
longest simple downward path from the node to a leafHeight of a node in a heap is the number of edges in the
Height of a heap of
n
elements is Θ(log
(^) n
). Why?
Q: How to maintain the heap property?
Max-Heapify
is given an array and an index
i .
Assumes
that the binary trees rooted at
Lef t
i ) and
Right
i ) are max-
heaps, but
i ] may be smaller than its children.
Max-Heapify
ensures that after its call, the subtree rooted
at
i
is a Max-Heap
down the element that start atMain idea of the Max-Heapify algorithm is that it percolates
i ] to the point where the
subtree rooted at
i
is a max-heap
To do this, it repeatedly swaps
i ] with its largest child until
i ] is bigger than both its children
For simplicity, the algorithm is described recursively.
Max-Heapify (A,i)
Lef t
i )
r
=
Right
i )
largest
i
l ≤
heap-size(
) and
l ]
A
i ]) then
largest
l
r ≤
heap-size(
) and
r ]
A
largest
]) then
largest
r
largest
i
then
(b) Max-Heapify (A,largest)(a) exchange A[i] and A[largest]
11
4
2
1
7
3
5
11
4
2
1
9
7
3
5
11
4
2
1
9
7
3
8
5
6
6
6
9
8
8
i
Let
h )
be
the
runtime
of
max-heapify
on
a
subtree
of
height
h
Then
h ) =
h (^) −
Solution to this recurrence is
h ) = Θ(
h )
Thus if we let
n ) be the runtime of max-heapify on a sub-
tree of
size
n ,
T (^) ( n ) =
(log
(^) n
), since log
(^) n
is the maximum
height of heap of size
n
Initialization:
i
=
b n/
c
prior to first iteration.
But each
node
b n/
c (^) + 1,
b n/
c (^) + 2,... ,
n
is a leaf so is the root of a
trivial max-heap
Termination:
At termination,
i = 0, so each node 1
,... , n
is the root of a max-heap.
In particular, node 1 is the root
of a max heap.
Maintenance:
First note that if the nodes
i (^) + 1,...
(^) n
are the
they will be the roots of max-heaps after the call.roots of max-heaps before the call to Max-Heapify (A,i), then
Further
note that the children of node
i
are numbered higher than
i
Thus after the call to Max-Heapify (A,i), the node and thus by the loop invariant are both roots of max heaps.
i
is the
root of a max-heap. Hence, when we decrement
i
in the for
loop, the loop invariant is established.
(Naive) Analysis:
Max-Heapify takes
(log
(^) n
) time per call
There are
n ) calls to Max-Heapify
Thus, the running time is
n (^) log
(^) n
)
Better Analysis. Note that:
An
n
element heap has height no more than log
(^) n
There are at most
n/
h
nodes of any height
h
(to see this,
consider the min number of nodes in a heap of height
h )
Time
required
by
Max-Heapify
when
called
on
a
node
of
height
h
is
h ).
Thus total time is:
∑
log
(^) n
n
2 h
h )
log
(^) n
∑
n
h
h )
n
log
(^) n
∑
h
h
n
∑ ∞
h
h
n )
The last step follows since for all
x | <
∑ ∞ i =
ix
x
(^) x
) 2
Can get this equality by recalling that for all
x | <
∑ ∞ i =
x i =
(^) x
,
and taking the derivative of both sides!
Heap-Sort (A)
i >
i − −
(c) Max-Heapify (A,1)(b) heap-size (A) = heap-size (A) - 1(a) do exchange A[1] and A[i]
Build-Max-Heap takes
n ), and each of the
n ) calls to
Max-Heapify take
(log
(^) n
), so Heap-Sort takes
n (^) log
(^) n
)
Correctness???