Comp210 Lecture # 31    Fall 2002

set-[struct]-[field]!

So, what does the hand-evaluation of

(cons 3 (cons 4 (cons 5 empty)))
look like? How about for
(cons (make-cat 'morris 93) (cons (make-cat 'garfield 87) empty))
What if , as in previous lectures, cats had an additional field bestbuddy refering to a cat?

Exercise: make the smallest example of you can, of a structure which somehow contains a reference to itself. (How does it print out? Remember shared from last lecture.)

Graphs ("trees with cycles")

(tentative)

How would we represent a map of the US, before we had mutating structures? How can we make them more properly, now?

(define-struct city (name nhbrs seen?))
;;
;; A city is a 
;; (make-city [symbol] [list-of-cities] [boolean])
;; where seen? is to be used later, in path-finding.

; Initially no neighbors:
(define nyc  (make-city 'nyc  empty false))
(define la   (make-city 'la   empty false))
(define slc  (make-city 'slc  empty false))
(define hou  (make-city 'houston empty false))
(define nome (make-city 'nome empty false))
(define reno (make-city 'reno empty false))

(define cities (list nyc la slc hou nome reno))


(set-city-nhbrs! nyc  (list la slc hou nyc))
(set-city-nhbrs! la   (list reno slc nyc))
(set-city-nhbrs! hou  (list nyc la))
(set-city-nhbrs! slc  (list reno))
(set-city-nhbrs! reno (list slc))

What is our algorithm for searching?

;; path: city, city --> list-of-city or false
;; Return false if no path, otherwise return
;; a path which includes both endpoints.
;;
(define (path src dest)
  (cond [(eq? src dest) (list src)]
        [else (local {(define otherways (map (lambda (s) (path s dest))
                                        (city-nhbrs src)))
                      (define viable-otherways (filter list? otherways))}
                (cond [(empty? viable-otherways) false]
                      [else (cons src (first viable-otherways))]))]))



;;; Alternate version of path, w/o using map or fold:
;;
(define (path src dest)
  (cond [(eq? src dest) (list src)]
        [else (local {(define otherway (path-from-list (city-nhbrs src) dest))}
                 (if (list? otherway)
                     (cons src otherway)
                     false))]))

;; path-from-list: list-of-city, city --> list-of-city or false
;; Return either a path from one of srcs to dest,
;; or false if no such path exist from anybody in srcs.
;;
(define (path-from-list srcs dest)
  (cond [(empty? srcs) false]
        [else (local [(define try-first (path (first srcs) dest))]
                 (if (list? try-first)
                     try-first
                     (path-from-list (rest srcs) dest)))]))

(path slc nyc) = 
;;  Uh-oh, runs forever!
;;  Hand-evaluation reveals
;;  It's checking slc, reno, slc, reno, slc, ...
N.B. Instead of a separate function path-from-list, we could instead mapped "find a path to dst" on each of the cities neighbors, and then grabbed the first element from all these solutions (or, checked if map returned a list containing only false from each neighbor). Same diff.

What do we need to do, to avoid loops?

;; path: city, city --> list-of-city or false
;; Return false if no path, otherwise return
;; a path which includes both endpoints.
;;
(define (path src dest)
  (cond [(eq? src dest) (list src)]
        [(city-seen? src) false] ; Already visited, so don't go here again.
        [else 
         (begin
           (set-city-seen?! src false)
           (local [(define otherway (path-from-list (city-nhbrs src) dest))]
             (if (list? otherway)
                  (cons src otherway)
                  false))]))


(find-path slc nyc) = false
(find-path nyc slc) = ; nyc -> la -> slc, printed in "shared" form.
 ; Note, it's not the shortest path.
(code)

This approach is called "depth-first search": it searches the first neighbor, and the first of that neighbor, and ... and backtracks when it reaches a dead end (or something seen before).

A fundamentally different way of finding a path from one place to another is "breadth-first search": look at all places one step away from src, then two steps away, then three steps, ... This method is guaranteed to always return a shortest path (can you seen why?).

 

©2002 Ian Barland