Docsity
Docsity

Prepare for your exams
Prepare for your exams

Study with the several resources on Docsity


Earn points to download
Earn points to download

Earn points by helping other students or get them with a premium plan


Guidelines and tips
Guidelines and tips

Proving Algorithm Correctness using Loop Invariants and Heap Data Structures, Study notes of Computer Science

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

Pre 2010

Uploaded on 07/22/2009

koofers-user-fn7
koofers-user-fn7 🇺🇸

10 documents

1 / 8

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
CS 361, Lecture 8
Jared Saia
University of New Mexico
Outline
“Partly because of his computational skills, Gerbert, in his later
years, was made Pope by Otto the Great, Holy Roman Emperor,
and took the name Sylvester II. By this time, his gift in the art of
calculating contributed to the belief, commonly held throughout
Europe, that he had sold his soul to the devil.”
- Dominic Olivastro in the book Ancient Puzzles, 1993
Loop Invariants
Binary Heaps
1
Correctness of Algorithms
The most important aspect of algorithms is their correctness
An algorithm by definition always gives the right answer to
the problem
A procedure which doesn’t always give the right answer is a
heuristic
All things being equal, we prefer an algorithm to a heuristic
How do we prove an algorithm is really correct?
2
Loop Invariants
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
3
pf3
pf4
pf5
pf8

Partial preview of the text

Download Proving Algorithm Correctness using Loop Invariants and Heap Data Structures and more Study notes Computer Science in PDF only on Docsity!

CS 361, Lecture 8

Jared Saia

University of New Mexico

Outline

  • Dominic Olivastro in the bookEurope, that he had sold his soul to the devil.”calculating contributed to the belief, commonly held throughoutand took the name Sylvester II. By this time, his gift in the art ofyears, was made Pope by Otto the Great, Holy Roman Emperor, “Partly because of his computational skills, Gerbert, in his later

Ancient Puzzles

Loop Invariants

Binary Heaps

Correctness of Algorithms

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?

Loop Invariants

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

Example Loop Invariant

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)

Example Algorithm

GetMiddle (List l){

while ((pFast->next)&&(pFast->next->next)){pSlow = pFast = l;

pSlow = pSlow->nextpFast = pFast->next->next

return pSlow}

Example Loop Invariant

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)

  1. Thus pSlow points to the middle of the list

Challenge

a loop in a linked listFigure out how to use a similar idea to determine if there is

without marking nodes!

Max-Heap Property

For every node

i

other than the root, A[Parent (i)]

A[i]

Max-Heap Property

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)

Height of Heap

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?

Maintaining Heaps

Q: How to maintain the heap property?

A:

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

A

[

i ] may be smaller than its children.

Max-Heapify

ensures that after its call, the subtree rooted

at

i

is a Max-Heap

Max-Heapify

down the element that start atMain idea of the Max-Heapify algorithm is that it percolates

A

[

i ] to the point where the

subtree rooted at

i

is a max-heap

To do this, it repeatedly swaps

A

[

i ] with its largest child until

A

[

i ] is bigger than both its children

For simplicity, the algorithm is described recursively.

Max-Heapify

Max-Heapify (A,i)

l

Lef t

i )

r

=

Right

i )

largest

i

  1. if (

l ≤

heap-size(

A

) and

A

[

l ]

A

[

i ]) then

largest

l

  1. if (

r ≤

heap-size(

A

) and

A

[

r ]

A

[

largest

]) then

largest

r

  1. if

largest

i

then

(b) Max-Heapify (A,largest)(a) exchange A[i] and A[largest]

Example

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

Analysis

Let

T

h )

be

the

runtime

of

max-heapify

on

a

subtree

of

height

h

Then

T

T

h ) =

T

h (^) −

Solution to this recurrence is

T

h ) = Θ(

h )

Thus if we let

T

n ) be the runtime of max-heapify on a sub-

tree of

size

n ,

T (^) ( n ) =

O

(log

(^) n

), since log

(^) n

is the maximum

height of heap of size

n

Correctness

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

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.

Time Analysis

(Naive) Analysis:

Max-Heapify takes

O

(log

(^) n

) time per call

There are

O

n ) calls to Max-Heapify

Thus, the running time is

O

n (^) log

(^) n

)

Time Analysis

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

O

h ).

Thus total time is:

log

(^) n

h

n

2 h

O

h )

Analysis

log

(^) n

h

n

h

O

h )

O

  n

log

(^) n

h

h

h  

O

  n

∑ ∞

h

h

h  

O

n )

Analysis

The last step follows since for all

x | <

∑ ∞ i =

ix

i

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

Heap-Sort (A)

  1. for (i=length (A);1. Build-Max-Heap (A)

i >

i − −

(c) Max-Heapify (A,1)(b) heap-size (A) = heap-size (A) - 1(a) do exchange A[1] and A[i]

Analysis

Build-Max-Heap takes

O

n ), and each of the

O

n ) calls to

Max-Heapify take

O

(log

(^) n

), so Heap-Sort takes

O

n (^) log

(^) n

)

Correctness???