Graduate Program KB

SICP

Chapter 1.2

Linear Recursion and Iteration

  • Linear recursive processes involve a sequence of deferred operations, each step requiring the previous to complete
    • Stack space grows linearly as the number of recursive calls increase
    • Notice in the example, the else case multiples n and the result of a recursive call. The operand * must be stored then applied once the call is computed
(define (factorial n)
    (if (= n 1)
    1
    (* n (factorial (- n 1)))))
  • Linear iterative processes only track a set number of variables, updating them and passing them to the next call
    • Fixed amount of memory
    • product is the current total, counter is the current iteration and max-count informs the algorithm at which iteration to stop
(define (factorial n)
    (fact-iter 1 1 n))

(define (fact-iter product counter max-count)
    (if (> counter max-count)
    product
    (fact-iter (* counter product)
               (+ counter 1)
                max-count)))

Tree Recursion

  • Tree recursive processes involve multiple recursive calls at each step which form branches similar to a tree
    • Since each call can generate many additional branches, the run time can become exponential
    • Notice in Ackermann's function, in the else case, there are two recursive calls which form two branches in the tree at each step
    • This results in an exponential run time of O(2n)
(define (A x y)
    (cond ((= y 0) 0)
          ((= x 0) (* 2 y))
          ((= y 1) 2)
          (else (A (- x 1) (A x (- y 1))))))

Orders of growth

  • Describe time and space requirements of a function based off input size, it provides insight of an algorithm's efficiency and scalability
  • The most common orders of growth include: O(1), O(log n), O(n2), O(2n)

Exponents

  • Raising base to power using a linear process
(define (expt b n)
    (if (= n 0)
    1
    (* b (expt b (- n 1)))))
  • Recursive exponentiation can use a divide and conquer strategy (successive squaring) to reduce the problem size by half with each recursive call
    • Order of growth becomes logarithmic (O(log n))
(define (fast-expt b n)
    (cond ((= n 0) 1)
          ((even? n) (square (fast-expt b (/ n 2))))
          (else (* b (fast-expt b (- n 1))))))

(define (even? n)
    (= (remainder n 2) 0))
  • Example of successive squaring:

    • b2 = b * b
    • b4 = b2 * b2
    • b8 = b4 * b4
  • If the power is odd, then decrement it to an even power and apply a multiplication of the base to the final result

Other

  • In Dr Racket, add to use the in-built procedure current-inexact-milliseconds to calculate runtime
#lang racket/base
  • For iteration, define a helper function which won't affect our signature call
  • Therefore, our program can still work despite a different algorithmic implementation which may require new parameters
  • For example, calculating factorials iteratively requires 3 parameters compared to 1, and two of them have initial values of 1:
; Recursive
(define (factorial n) ( ... ))

; Iterative
(define (factorial n)) (
    (fact-iter 1 1 n)
)

(define (fact-iter product count max-count) ( ... ))