daily puzzle - · pdf filethe josephus problem

31
Lecture 24 The mysteries of recursion Daily Puzzle

Upload: phamcong

Post on 28-Feb-2018

228 views

Category:

Documents


6 download

TRANSCRIPT

Page 1: Daily Puzzle -   · PDF fileThe Josephus Problem

Lecture 24The mysteries of recursion

Daily Puzzle

Page 2: Daily Puzzle -   · PDF fileThe Josephus Problem

Recursion

• The process of recursion may have had its birth in literature. For example, the poem “Sacred Emily”, by Gertrude Stein (1913):

A rose is a rose is a rose

is a rose.

The Droste Effect

• A Dutch term for a specific kind of recursive picture in which an image depicts a smaller version of itself in a place where a similar picture would realistically be expected to appear.

Page 3: Daily Puzzle -   · PDF fileThe Josephus Problem
Page 4: Daily Puzzle -   · PDF fileThe Josephus Problem

Recursion in Nature

• Structures in nature that contain substructures with the same form as the whole exhibit something known as “self-similarity”.

Page 5: Daily Puzzle -   · PDF fileThe Josephus Problem

Visual recursion

• Recursion is used to generate fractals

“a rough or fragmented geometric shape that can be split into parts, each of which is (at least approximately) a reduced-size copy of the whole”.

Hilbert curves

• A continuous fractal space-filling curve first described by the German mathematician David Hilbert (1862-1943) in 1891.

Page 6: Daily Puzzle -   · PDF fileThe Josephus Problem

Hilbert curves

Koch snowflake

• One of the earliest fractals, derived from the Koch curve of 1904 by Swedish mathematician Helge von Koch.

Page 7: Daily Puzzle -   · PDF fileThe Josephus Problem

Koch snowflake

Cesaro curve, based on Koch infrastructure

Recursion

• Recursion is a programming technique that naturally implements the divide-and-conquer programming methodology.

Page 8: Daily Puzzle -   · PDF fileThe Josephus Problem

Barron, in his monograph entitled “Recursive Techniques in

Programming” (1968) said:

“if computers had existed in the Middle Ages, programmers would have been burned at the stake by

other programmers for heresy”

...“it is certain that one of the main heresies would have

been a belief (or disbelief) in recursion”

How is it performed?

• The notion of recursion is linked to the idea of a stack.

• Edsger Dijkstra first described this in 1960.

Page 9: Daily Puzzle -   · PDF fileThe Josephus Problem

A STACK WORKS LIKE A PEZ DISPENSER

LIFO - Last-In, First-Out

Items are added by being pushed onto the stack, and

removed by being popped off the stack

A STACK FOR A RUNNING C

PROGRAM USING A RECURSIVE

FUNCTION X.

The stack is used to store a stack frame for each function

that has been called.

static variables

main()

function X called from main()

function X_1 called from X

function X_2 called from X_1

current stack frame

Note that stacks have finite storage.

Page 10: Daily Puzzle -   · PDF fileThe Josephus Problem

How does it work?

if (this is a simple case) solve itelse redefine the problem using recursionend if

! Calculating xn

! e.g. x5 = x * x * x * x * x

! and is broken down as:

! x * (x * x * x * x)! x * (x * (x * x * x))! x * (x * (x * (x * x)))! x * (x * (x * (x * (x))))

Page 11: Daily Puzzle -   · PDF fileThe Josephus Problem

Is recursion useful?

• Depends on the problem being solved.

• Is it a recursive problem?

• If not, does a recursive solution offer simplicity, or efficiency?

Many types of recursion

• Linear recursion.

• Binary recursion.

• Nested recursion.

• Mutual recursion.

Page 12: Daily Puzzle -   · PDF fileThe Josephus Problem

Is recursion good?

• Yes, but not always.

• Some recursive solutions are ubiquitous... - but horrible.

• Don’t use recursion just for the sake of using recursion.

Fibonacci

• Classic, yet “naïve” binary recursive form of deriving Fibonacci numbers.

• Used in nearly every textbook containing recursion.

• It works but at what cost?

Page 13: Daily Puzzle -   · PDF fileThe Josephus Problem

Version of Fibonacci algorithm in C:

int fib(int n){ if (n <= 2) return 1; else return fib(n-1) + fib(n-2);}

fib(5)

fib(4) fib(3)

fib(3) fib(2) fib(2) fib(1)

1fib(2) fib(1)

1

1 1

1

+

+

+

+

Page 14: Daily Puzzle -   · PDF fileThe Josephus Problem

Fibonacci

• The algorithm grows in exponential time.

• Calculating fib(200) requires approximately 2140 operations.

• Biggest problem is time spent recalculating already calculated numbers.

Fibonacci

Put into perspective:

Fujitsu K computer @ 10.51 petaflops10.51×1015 floating-point ops / sec

2140 = 1.3×1026 seconds≈ 4.2×1016 millennia

Page 15: Daily Puzzle -   · PDF fileThe Josephus Problem

Fibonacci

Calculating fib(40):fib(35) calculated 8 times, and

fib(1 or 2) calculated 102,334,155 times.

Total = 204,668,309 function calls

A better way - linear recursion?

int fib(int a, int b, int n){ if (n <= 2) return b; else if (n > 2) return fib(b,a+b,n-1);}

called using f = fib(1,1,n)

for n=40 39 function calls total

0 seconds

Page 16: Daily Puzzle -   · PDF fileThe Josephus Problem

A mutually recursive way

for n=40 120 seconds

int fib_babies(int i){ if (i == 1) return 1; else return fib_adults(i-1);}

int fib_adults(int i){ if (i == 1) return 0; else return fib_adults(i-1) + fib_babies(i-1);}

Rubio and Pajak

called using f = fib_adults(n) + fib_babies(n);

A quick recursive way

for n=40 63 recursive calls,

0 seconds

Dijkstra / Shortt

long long fib_DijkstraR(int n){! long long i,j,tempi,tempj;! if (n == 0)! ! return 0;! if (n == 1)! ! return 1;

! if (n%2 == 0){ //even! ! i = (n-1) / 2;! ! j = n / 2;! ! tempi = fib_DijkstraR(i);! ! tempj = fib_DijkstraR(j);! ! return (2 * tempi + tempj) * tempj;! }! else { //odd! ! i = n / 2;! ! j = (n+1) / 2;! ! tempi = fib_DijkstraR(i);! ! tempj = fib_DijkstraR(j);! ! return tempi * tempi + tempj * tempj;! }}

Page 17: Daily Puzzle -   · PDF fileThe Josephus Problem

A quick recursive way

CAREFUL!!

Dijkstra / Shortt

tempi = fib_DijkstraR(i);tempj = fib_DijkstraR(j);return (2 * tempi + tempj) * tempj;

DO THIS

return (2 * fib_DijkstraR(i) + fib_DijkstraR(j)) * fib_DijkstraR(j);

NOT THIS!

Towers of Hanoi

• A classic CS example of recursion.

• Simple to implement...harder to conceptualize.

Page 18: Daily Puzzle -   · PDF fileThe Josephus Problem

The puzzle was invented by the French mathematician

François Édouard Anatole Lucas (1842-1891) in 1883.

TofH recursive algorithm in C

void hanoiR(int N, int from, int to, int using){ if (N > 0) { hanoiR(N-1, from, using, to); printf("move %d -> %d\n", from, to); hanoiR(N-1, using, to, from); }}

called using hanoiR(3, 1, 3, 2);

Page 19: Daily Puzzle -   · PDF fileThe Josephus Problem

hanoiR(3, 1, 3, 2)!! hanoiR(2, 1, 2, 3) ! ! hanoiR(1, 1, 3, 2)! ! ! hanoiR(0, 1, 2, 3) -> recursion terminates! ! move 1 -> 3! ! ! hanoiR(0, 2, 3, 1) -> recursion terminates! ! move 1 -> 2! ! hanoiR(1, 3, 2, 1)! ! ! hanoiR(0, 3, 1, 2) -> recursion terminates! ! ! move 3 -> 2! ! ! hanoiR(0, 1, 2, 3) -> recursion terminates! move 1 -> 3! hanoiR(2, 2, 3, 1)! ! hanoiR(1, 2, 1, 3)! ! ! hanoiR(0, 2, 3, 1) -> recursion terminates! ! ! move 2 -> 1! ! ! hanoiR(0, 3, 1, 2) -> recursion terminates! ! move 2 -> 3! ! hanoiR(1, 1, 3, 2)! ! ! hanoiR(0, 1, 2, 3) -> recursion terminates! ! ! move 1 -> 3! ! ! hanoiR(0, 2, 3, 1) -> recursion terminates

Iterative approaches?

• Using stacks.

• Using 2D arrays.

• A *lot* more code, and algorithm complexity.

Page 20: Daily Puzzle -   · PDF fileThe Josephus Problem

#include <stdio.h>

int disk[3][3] = {{1,0,0},{1,0,0},{1,0,0}};

void print_tower(){ printf("%d %d %d\n", disk[0][0], disk[0][1], disk[0][2]); printf("%d %d %d\n", disk[1][0], disk[1][1], disk[1][2]); printf("%d %d %d\n", disk[2][0], disk[2][1], disk[2][2]); printf("\n");}

// Function to determine if all the disks have been movedint is_moved(void){ if (disk[0][2] == 1 && disk[1][2] == 1 && disk[2][2] == 1) return 1; else { return 0; }}

// Function to determine the index, moving counter-clockwiseint ccw(int index){ if (index == 0) return 2; else return index - 1;}

// Function to determine the tower position of the smallest// diskint find_smallest_disk(void){ int disc; if (disk[0][0] == 1) disc = 0; else if (disk[0][1] == 1) disc = 1; else if (disk[0][2] == 1) disc = 2; return disc;}

// Function to return the tower position of the next disk to move.

void find_next_disk(int *disc, int *tower){

int i,j,k,found=1,df,su,disc_pos;

i = 1; while (i <= 2) {

// Check each disc row below the top to find a disc to move j = 0; df = 0; while (j <= 2) { if (disk[i][j] == 1) { df = 1; disc_pos = j; break; } else j = j + 1; } // Check the disc to make sure it can be moved

su = 0; for (k=i-1; k>=0; k=k-1) su = su + disk[k][disc_pos];

if (su == 0) { *disc = i; *tower = disc_pos; break; } else i = i + 1; }}

// Function to move the disk

void move_disk(int disc, int from, int to){ disk[disc][from] = 0; disk[disc][to] = 1;}

int main (void){ int smallest, d, disc, tower;

smallest = find_smallest_disk(); d = ccw(smallest); move_disk(0,smallest,d);

while (!is_moved()) { print_tower();

find_next_disk(&disc, &tower); if (disc == 1){ d = ccw(tower); d = ccw(d); } else if (disc == 2) d = ccw(tower);//printf("%d %d %d\n", disc, tower, d);

move_disk(disc,tower,d); print_tower();

smallest = find_smallest_disk(); d = ccw(smallest); move_disk(0,smallest,d); } print_tower();

return 0;}

Many other algorithms

• Mergesort, Quicksort.

• Greatest common divisor.

• Factorial.

• Palindrome, 8-Queens.

• Maze searching,

• Solving Sudoku.

Page 21: Daily Puzzle -   · PDF fileThe Josephus Problem

Ackermann’s Function

• Originated in 1928.

• Used extensively for studies in computational efficiency.

• Highly recursive.

• But - few real applications.

Ackermann’s Function

Page 22: Daily Puzzle -   · PDF fileThe Josephus Problem

Ackermann’s Function

A(1,2)= A(0, A(1,1))= A(0, A(0, A(1,0)))= A(0, A(0, 2))= A(0, 3)= 4

Ackermann’s Function

! int ackermann(int m, int n)! {! ! if (m == 0) ! return(n+1);! ! else if (n == 0) ! return(ackermann(m-1,1));! ! else ! return(ackermann(m-1,ackermann(m,n-1)));! } !

nested recursion

Page 23: Daily Puzzle -   · PDF fileThe Josephus Problem

Ackermann’s Function

• Can be used to illustrate recursive depth.

• Ackermann(2,2) produces the following recursive structure...

A(2,2)A(1,A(2,1))A(1,A(1,A(2,0)))A(1,A(1,A(1,1)))A(1,A(1,A(0,A(1,0))))A(1,A(1,A(0,A(0,1))))A(1,A(1,A(0,2)))A(1,A(1,3))A(1,A(0,A(1,2)))A(1,A(0,A(0,A(1,1))))A(1,A(0,A(0,A(0,A(1,0)))))A(1,A(0,A(0,A(0,A(0,1)))))A(1,A(0,A(0,A(0,2))))A(1,A(0,A(0,3)))A(1,A(0,4))A(1,5)A(0,A(1,4))A(0,A(0,A(1,3)))A(0,A(0,A(0,A(1,2))))A(0,A(0,A(0,A(0,A(1,1)))))A(0,A(0,A(0,A(0,A(0,A(1,0))))))A(0,A(0,A(0,A(0,A(0,A(0,1))))))A(0,A(0,A(0,A(0,A(0,2)))))A(0,A(0,A(0,A(0,3))))A(0,A(0,A(0,4)))A(0,A(0,5))A(0,6)7

Page 24: Daily Puzzle -   · PDF fileThe Josephus Problem

Ackermann’s Function

• Cannot be computed with only definite iteration (a completely defined for loop for example).

• Can be solved using a complex stack.

Ackermann’s Function

Ackermann(4,1)=6553331.85 s

Nonrecursive algorithm using a stack 91.17 s

Page 25: Daily Puzzle -   · PDF fileThe Josephus Problem

Pitfalls of recursion

• No guarantee of convergence.

• Excessive space requirements.

• Excessive re-computation.

• Laborious debugging.

Recursion and problem solving

• Look at various approaches to solving a problem.

• Is recursion the best solution?

Page 26: Daily Puzzle -   · PDF fileThe Josephus Problem

The Josephus Problem

• Originates from Roman historian Flavius Josephus (37-100).

• Basically a “reduction using a step of size k” problem.

The Josephus Problem

• A group of n people are standing in a circle, numbered consecutively clockwise from 1 to n.

• Starting with the first person, every kth person is removed, proceeding clockwise.

• What is the position of the remaining survivor?

Page 27: Daily Puzzle -   · PDF fileThe Josephus Problem

The Josephus Problem

If n = 6, and k=2, then people are removed in the following order:

2, 4, 6, 3, 1

the last person remaining is no. 5.

The Josephus Problem

➏ ×

×

×

×

×

Page 28: Daily Puzzle -   · PDF fileThe Josephus Problem

➌➎

➌➎

➎ ➎

×

×

×

×

×

The Josephus Problem

• What’s the best algorithm to use?

Page 29: Daily Puzzle -   · PDF fileThe Josephus Problem

The Josephus Problem

• The structure is circular, so a circular array, or linked list is the easiest.

• The problem can also be solved recursively... it’s just trickier.

The Josephus Problem

!int josephus(int n)!{!! if (n == 1)!!! return 1;!! if (n % 2 == 0)!!! return 2 * josephus(n / 2) - 1;!! else!!! return 2 * josephus(n / 2) + 1;!}

works for removing every 2nd person.

Page 30: Daily Puzzle -   · PDF fileThe Josephus Problem

Car Parking

Car Parking

void park(double lower, double upper){ double p; p = drand_RANGE(lower,upper); num = num + 1; printf("Car parked at position %.1f\n", p); if ((p-0.5)-(lower-0.5) >= 1.0) park(lower,p-1.0); if ((upper+0.5)-(p+0.5) >= 1.0) park(p+1.0,upper);}

park(0.5,9.5);

initial c

all

Page 31: Daily Puzzle -   · PDF fileThe Josephus Problem

Car Parking

double drand_RANGE(double low, double high){ int randomNum; double drand, span;! randomNum = (double)rand(); drand = randomNum / (double) RAND_MAX; span = high - low; return low + span * drand;}

derive random numbers between low and high