260 likes | 272 Views
מבוא מורחב למדעי המחשב בשפת Scheme. תרגול 5. List Utilities. Scheme built-in procedures (list x y z ...) (list-ref lst index) (length lst) (append lst1 lst2) Built-in append can take any number of lists (map proc lst)
E N D
List Utilities • Scheme built-in procedures • (list x y z ...) • (list-ref lst index) • (length lst) • (append lst1 lst2) • Built-in append can take any number of lists • (map proc lst) • Built in map can take any number of lists, and a multi-variable procedure
(lambda (x y) <body>) x – list element y – accumulated result for rest of list <body> - update y with new element x Return value for empty list More Utilities • Non built-in procedures • (enumerate-interval from to) • Sometimes named integers-between • (filter pred lst) • (accumulate op init lst)
accumulate (define (accumulate proc init lst) (if (null? lst) init (proc (car lst) (accumulate proc init (cdr lst))))) (accumulate + 0 (list 1 2 3 4 5)) (accumulate * 1 (list 1 2 3 4)) (accumulate cons null (list 1 2 3)) (accumulate append null (list (list 1 2) (list 3 4) (list 5))) 15 24 (1 2 3) (1 2 3 4 5)
Solving the puzzle • Input: board size • Output: list of solutions • Need to determine: • Algorithm • Board abstraction • Putting it together
Queen Algorithm • Observation: One queen in each column • Placing k queens on k columns: • Find all solutions for k-1 • For each partial solution, add a column • Enumerating over all column positions for new queen • Remove illegal solutions
Add a queen (adjoin-position new-row rest-of-queens) Implementation depends on board abstraction Add column with queen Queen’s position in column Partial solution
In every row (map (lambda (new-row) (adjoin-position new-row rest-of-queens)) (enumerate-interval 1 board-size)) Adjoin partial solution To every possible row
To every partial solution (map (lambda (rest-of-queens) (map (lambda (new-row) (adjoin-position new-row rest-of-queens)) (enumerate-interval 1 board-size))) (queen-cols (- k 1)))) Enumerate Partial solutions
Flatten list of lists Each solution in the list is extended to a list of possible solutions (with an extra column) (accumulate append null (map (lambda (rest-of-queens) (map (lambda (new-row) (adjoin-position new-row rest-of-queens)) (enumerate-interval 1 board-size))) (queen-cols (- k 1))))
Deleting illegal solutions (filter (lambda (positions) (safe? positions)) (accumulate append null (map (lambda (rest-of-queens) (map (lambda (new-row) (adjoin-position new-row rest-of-queens)) (enumerate-interval 1 board-size))) (queen-cols (- k 1))))) Implementation depends on board abstraction
Everything else (define (queens board-size);; Main procedure (define (queen-cols k) ;; Solve for k columns (if (= k 0) ;; Stop condition (list empty-board) ;; Basic solution (depends on abstraction) (filter (lambda (positions) (safe? positions)) (accumulate append null (map (lambda (rest-of-queens) (map (lambda (new-row) (adjoin-position new-row rest-of-queens)) (enumerate-interval 1 board-size))) (queen-cols (- k 1))))))) (queen-cols board-size)) ;; Initial call
Board Abstraction • List of queen positions • Don’t represent empty columns • Add next queen to the left • Tailored to the algorithm’s needs • Can’t represent other board settings
Basic features (define empty-board null) (define (adjoin-position new-row rest-of-board) (cons new-row rest-of-board)) (define (first-position board) (car board)) (define (rest-positions board) (cdr board)) (define (empty? board) (null? board))
The safe? predicate • Check only the leftmost queen • Rest of board was verified before • Compare to every other queen: • Different row • Different diagonals
Possible Implementation (define (safe? positions) (define (verify first rest shift) (or (empty? rest) (let ((second (first-position rest))) (and (not (= first second)) (not (= first (+ second shift))) (not (= first (- second shift))) (verify first (rest-positions rest) (+ shift 1)))))) (verify (first-position positions) (rest-positions positions) 1))
b a t b s trie4 t e s e k k trie2 trie1 trie3 Trie A trie is a tree with a symbol associated with each arc. All symbols associated with arcs exiting the same node must be different. A trie represents the set of words matching the paths from the root to the leaves (a word is simply a sequence of symbols). { sk , t } { be } { ask , at , be } {}
Available procedures (empty-trie)- The empty trie (extend-trie symb trie1 trie2)- A constructor, returns a trie constructed from trie2, with a new arc from its root, associated with the symbol symb, connected to trie1 (isempty-trie? trie)- A predicate for an empty trie (first-symbol trie)- A selector, returns a symbol on an arc leaving the root (first-subtrie trie) - A selector, returns the sub-trie hanging on the arc with the symbol returned from (first-symbol trie) (rest-trie trie)- A selector, returns the trie without the sub-trie (first-subtrie trie) and without its connecting arc
word-into-trie (define (word-into-trie word) (accumulate word ) ) (lambda (c t) (extend-trie c t empty-trie)) empty-trie
add-word-to-trie • (define (add-word-to-trie word trie) • (cond ((isempty-trie? trie) ) • ((eq? (car word) (first-symbol trie)) • ) • (else • )) (word-into-trie word) (extend-trie (car word) (add-word-to-trie (cdr word) (first-subtrie trie)) (rest-trie trie)) (extend-trie (first-symbol trie) (first-subtrie trie) (add-word-to-trie word (rest-trie trie))))
trie-to-words (define (trie-to-words trie) (if (isempty-trie? trie) (let ((symb (first-symbol trie)) (trie1 (first-subtrie trie)) (trie2 (rest-trie trie))) ) ) ) null (if (isempty-trie? trie1) (append (list (list symb)) (trie-to-words trie2)) (append (map (lambda(w) (cons symb w)) (trie-to-words trie1)) (trie-to-words trie2)))
sub-trie word trie (define (sub-trie word trie) (cond ((null? word) ) ((isempty-trie? trie) ) ((eq? (car word) ) ) (else ) ) ) _ trie ‘NO (first-symbol trie) (sub-trie (cdr word) (first-subtrie trie)) (sub-trie word (rest-trie trie))
count-words-starting-with (define (count-words-starting-with word trie) (let ((sub (sub-trie word trie))) ) ) (cond ((eq? sub 'NO) 0) ((isempty-trie? sub) 1) (else (length (trie-to-words sub))))
trie implementation (define empty-trie null ) (define (isempty-trie? trie) (null? trie) ) (define (extend-trie symb trie1 trie2) (cons (cons symb trie1) trie2) ) (define (first-symbol trie) (caar trie) ) (define (first-subtrie trie) (cdar trie) ) (define (rest-trie trie) (cdr trie) )