Você está na página 1de 31

Discrete Mathematics: lecture 15

Barbara Morawska

March 13, 2019


Iterative and recursive algorithms
Algorithm
I well-defined computational procedure
I transforms input into output
I a tool to solve a well-specified computational problem

Computational problem is given by:


Input: . . .
Output: . . .
Iterative and recursive algorithms
Example: sorting problem
Input: < a1 , a2 , . . . , an > (a sequence of n numbers)
Output:< a10 , a20 , . . . , an0 > (a permutation of < a1 , a2 , . . . , an > ),
such that a10 ≤ a20 ≤ · · · ≤ an0
Example: instance of a problem
Input: < 31, 41, 59, 26, 41, 58 > (a sequence of 6 numbers)
Output: < 26, 31, 41, 41, 58, 59 >
Iterative and recursive algorithms
Pseudocode conventions
I No "begin – end" statements. Replaced by indentation.
I "//" starts a comment
I Arrays. Array elements: A[i] – i’th element of an array A
I two dots indicate range of an array:
A[1..j] =< A[1], A[2], . . . , A[j] >
I Objects have attributes: array has attribute length, e.g.
A.length.
I variable is treated as a pointer:
I y = x (y is assigned the pointer x ), implies x .f = y .f ,
I x .f = 3 (x .f is assigned value 3) implies y .f = 3.
x .f .g ((x .f ).g)
I NIL – a pointer referring to nothing
I more......
Iterative and recursive algorithms
Recursive algorithm
An algorithm is called recursive if it solves a problem by reducing it
to an instance of the same problem called on the smaller input.
I Base case (when the computation ends)
I Recursive step: reduction of the input and call to the same
procedure

Notice: recursive algorithm contains a call to the same algorithm


inside its body.
Iterative algorithm
Iterative algorithm is every algorithm that is not recursive.
Iterative and recursive algorithms
Algorithm to compute (output) factorial n!, for an input: n, a
non-negative integer.
Iterative version
Algorithm 1: factorial
Input : n – a non-negative integer
Output: n!
1 if n = 0 then
2 return 1
3 else
4 value = 1
5 for j = 1 to n do
6 value = j ∗ value
7 return value
Iterative and recursive algorithms
Algorithm to compute (output) factorial n!, for an input: n, a
non-negative integer.
Recursive version
Recursive version follows the recursive definition of factorial:

F (0) = 1
F (n) = (n) ∗ F (n − 1)

Algorithm 2: factorial
Input : n – a non-negative integer
Output: n!
1 if n = 0 then
2 return 1
3 else
4 return n ∗ factorial(n − 1)
Iterative and recursive algorithms
Algorithm to compute n’th power of a.
Iterative version
Algorithm 3: power
Input : n – a non-negative integer, a – a non-zero real number
Output: an
1 if n = 0 then
2 return 1
3 else
4 result ← 1
5 for j = 1 to n do
6 value ← a ∗ value
7 return value
Iterative and recursive algorithms
Algorithm to compute n’th power of a.
Recursive version
Recursive version follows the recursive definition:
I Base case: a0 = 1
I Recursive step: an+1 = a ∗ an
Algorithm 4: power
Input : n – a non-negative integer, a – a non-zero real number
Output: an
1 if n = 0 then
2 return 1
3 else
4 return a ∗ power (n − 1, a)
Iterative and recursive algorithms
Algorithm to compute n’th Fibonacci number.
Iterative version
Algorithm 5: fibonacci
Input : n – a non-negative integer
Output: fn – n’th fibonacci number
1 if n = 0 then
2 return 0
3 else
4 previous1 ← 0
5 previous2 ← 1
6 for j = 1 to n − 1 do
7 next ← previous1 + previous2
8 previous1 ← previous2
9 previous2 ← next
10 return previous2
Iterative and recursive algorithms
Algorithm to compute n’th Fibonacci number.
Recursive version
Recursive version follows the recursive definition:
I f0 = 0, f1 = 1
I fn = fn−1 + fn−2
Algorithm 7: fibonacci
Input : n – a non-negative integer
Output: fn – n’th fibonacci number
1 if n = 0 then
2 return 0
3 else if n = 1 then
4 return 1
5 else
6 return fibonacci(n − 1) + fibonacci(n − 2)
Iterative and recursive algorithms
Recursive algorithm for Fibonacci number is not optimal.
Look at the tree of computations for f4 performed by recursive
algorithm:
f4

f3 f2

f2 f1 f1 f0

f1 f0
f2 is computed two times!
Iterative and recursive algorithms
Algorithm to compute gcd of two integers a, b.
Iterative version
Algorithm 8: gcd
Input : a – a positive integer, b– a positive integer
Output: gcd(a, b)
1 while a 6= b do
2 if a > b then
3 a ←a−b
4 else
5 b ←b−a
6 return a
Iterative and recursive algorithms
Algorithm to compute gcd of two integers a, b.
Recursive version
Algorithm 9: gcd
Input : a – a positive integer, b– a positive integer
Output: gcd(a, b)
1 //base case:
2 if a = b then
3 return a
4 //recursive step:
5 if a > b then
6 return gcd(a − b, b)
7 else
8 return gcd(a, b − a)

Notice how while-loop is replaced by recursive calls


Proof of correctness
Prove that the recursive algorithm for gcd is correct
I Base case: if a = b, then gcd(a, b) = a = b.
I Recursive step:
IH: for (a0 , b 0 ) lexicographically smaller than (a, b), gcd is
computed in a correct way.
I for a > b, have to show gcd(a, b) = gcd(a − b, b)
I for a < b, have to show gcd(a, b) = gcd(a, b − a)

a>b
We use definition of gcd:

g = gcd(a, b) iff g > 0 ∧ g|a ∧ g|b ∧ ∀x (x |a ∧ x |b → x ≤ g)


Proof of correctness
a > b, proving that gcd(a, b) = gcd(a − b, b).

Definition:
g = gcd(a, b) iff g > 0 ∧ g|a ∧ g|b ∧ ∀x (x |a ∧ x |b → x ≤ g)

I Assume g = gcd(a − b, b),


I By definition: g|b and g|a − b. Hence g|a − b + b, i.e. g|a.
I Let g 0 |a and g 0 |b, we show that g 0 ≤ g.
I By substituting g 0 for x in the definition:
g 0 |a ∧ g 0 |b → g 0 ≤ g.
I Hence by MP: g 0 ≤ g.
I Hence g = gcd(a, b) and by IH the algorithm is correct.

Inductive hypothesis plays here a similar role as an invariant for a


while-loop.
Iterative and recursive algorithms
Algorithm for searching a number in a list of integers.
Linear search – Iterative version
Algorithm 10: linear search
Input : x – an integer, a1 , a2 , . . . , an – distinct integers
Output: i the index of ai , where ai = x , or 0
1 i ←1
2 while i ≤ n and x 6= ai do
3 i ←i +1
4 if i ≤ n then
5 return i
6 else
7 return 0
Iterative and recursive algorithms
Algorithm for searching a number in a list of integers.
Linear search – Recursive version
Algorithm 11: linear search
Input : x , i = 1, j = n – integers, a1 , a2 , . . . , an – distinct integers
Output: i the index of ai , where ai = x , or 0
1 if x = ai then
2 return i
3 else if i = j then
4 return 0
5 else
6 search(x , i + 1, j, a1 , . . . , an )

Initially search should be called with i = 1, j = n.


Iterative and recursive algorithms
Algorithm for searching a number in a list of integers ordered in
the increasing order.
Binary search – Iterative version
Algorithm 12: binary search
Input : x – an integer, a1 , a2 , . . . , an – increasing integers
Output: i if ai = x , 0 otherwise
1 i ←1 //i is the left endpoint
2 j ←n //j is the right endpoint
3 while i < j do
4 m ← b(i + j)/2c
5 if x > am then
6 i ←m+1
7 else
8 j ←m
9 if x = ai then
10 return i
11 else
12 return 0
Iterative and recursive algorithms
Algorithm for searching a number in a list of integers ordered in
the increasing order.
Binary search – Recursive version
Algorithm 13: binary search
Input : x – an integer, a1 , a2 , . . . , an – increasing integers
Output: i if ai = x , 0 otherwise
1 m ← b(i + j)/2c
2 if x = am then
3 return m
4 else if x < am and i < m then
5 return binary serach(x , i, m − 1, a1 , a2 , . . . , an )
6 else if x > am and j > m then
7 return binary serach(x , m + 1, j, a1 , . . . , an )

Try iterative or recursive version on the input:


19 and 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 13, 15, 16, 18, 19, 20, 22
Tail-recursion
I Recursive call of an algorithm is costly: new portion of stack,
new process opened.
I This process can be closed, the stack space reused, only if the
call is exited.
I You can trace it in the execution of sum in Prolog.
I If the recursive call is the last call in the definition of an
algorithm, this algorithm is called tail-recursive.
I The stack frame for the old call can be reused for the next
call.
Factorial
The recursive version of factorial is not tail-recursive:
Algorithm 2: factorial
Input : n – a non-negative integer
Output: n!
1 if n = 0 then
2 return 1
3 else
4 return n ∗ factorial(n − 1)
Computation of factorial
Computation of factorial(5)

1. factorial(5)
2. 5 ∗ factorial(4)
3. 5 ∗ 4 ∗ factorial(3)
4. 5 ∗ 4 ∗ 3 ∗ factorial(2)
5. 5 ∗ 4 ∗ 3 ∗ 2 ∗ factorial(1)
6. 5 ∗ 4 ∗ 3 ∗ 2 ∗ 1 ∗ factorial(0)
7. 5∗4∗3∗2∗1∗1
8. 5∗4∗3∗2∗1
9. 5∗4∗3∗2
10. 5∗4∗6
11. 5 ∗ 24
12. 120
Factorial
Tail-recursive version
Algorithm 14: factTR
Input : n – a non-negative integer, result = 1
Output: n!
1 if n = 0 then
2 return result
3 else
4 return factTR(n − 1, result ∗ n)
Computation of factTR(5, 1)

1. factTR(5, 1)
2. factTR(4, 5)
3. factTR(3, 20)
4. factTR(2, 60)
5. factTR(1, 120)
6. factTR(0, 120)
7. 120
Power
Recursive version of power is not tail-recursive:
Algorithm 4: power
Input : n – a non-negative integer, a – a non-zero real number
Output: an
1 if n = 0 then
2 return 1
3 else
4 return a ∗ power (n − 1, a)

Tail recursive version of power


Algorithm 15: powerTR
Input : n – a non-negative integer, a – a non-zero real number,
result = 1
Output: an
1 if n = 0 then
2 return result
3 else
4 return powerTR(n − 1, a, a ∗ result)
Fibonacci
Recursive version of fibonacci is not tail-recursive:
Algorithm 8: fibonacci
Input : n – a non-negative integer
Output: fn – n’th fibonacci number
1 if n = 0 then
2 return 0
3 else if n = 1 then
4 return 1
5 else
6 return fibonacci(n − 1) + fibonacci(n − 2)
Fibonacci
In designing tail-recursive version we follow the idea from the
iterative version:
Algorithm 16: fibonacciTR(n,a = 0, b = 1)
Input : n–non-negative integer,a = 0, b = 1
Output: fn – n’th fibonacci number
1 if n = 0 then
2 return a
3 else if n = 1 then
4 return b
5 else
6 return fibonacciTR(n − 1, b, a + b)

Notice: f0 = 0, f1 = 1, f2 = 1, f3 = 2, f4 = 3, f5 = 5, . . .
gcd
The recursive version of gcd is tail-recursive:
Algorithm 9: gcd
Input : a – a positive integer, b– a positive integer
Output: gcd(a, b)
1 //base case:
2 if a = b then
3 return a
4 //recursive step:
5 if a > b then
6 return gcd(a − b, b)
7 else
8 return gcd(a, b − a)
Linear search
The recursive version of linear search is tail-recursive:
Algorithm 11: linear search
Input : x , i = 1, j = n – integers, a1 , a2 , . . . , an – distinct integers
Output: i the index of ai , where ai = x , or 0
1 if x = ai then
2 return i
3 else if i = j then
4 return 0
5 else
6 search(x , i + 1, j, a1 , . . . , an )
Binary search
The recursive version of binary search is tail-recursive:
Algorithm 13: binary search
Input : x – an integer, a1 , a2 , . . . , an – increasing integers
Output: i if ai = x , 0 otherwise
1 m ← b(i + j)/2c
2 if x = am then
3 return m
4 else if x < am and i < m then
5 return binary serach(x , i, m − 1, a1 , a2 , . . . , an )
6 else if x < am and j > m then
7 return binary serach(x , m + 1, j, a1 , . . . , an )

Você também pode gostar