;;; File: ;;; search.ss ;;; Author: ;;; Samuel A. Rebelsky ;;; Version: ;;; 1.0 of November 2000 ;;; Summary: ;;; A collection of procedures that can be used for searching. ;;; Contents: ;;; History: ;;; Tuesday, 14 November 2000 [v 1.0] ;;; Created ;;; Wednesday, 15 November 2000 [v 1.1] ;;; Added some sample lists. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Values ;;; Name: ;;; lastnames ;;; Type: ;;; Vector of strings ;;; Contents: ;;; Last names of the CSC151.02 2000F students (define lastnames (vector "Arnold" "Barnum" "Brown" "Cherry" "Evans" "Finnessy" "Griffin" "Hammouda" "Jamal" "Kmiec" "Knoernschild" "Koomjian" "Lieberman" "Omvig" "Perng" "Pervaiz" "Pinchback" "Rathsam" "Raulerson" "Romanelli" "Runyowa" "Schneider" "Sheikh" "Slagle" "Techavalitpongse" "Vanderhyden" "Wagner" "Walker" "Weiss" "Wellons" "Zhang")) ;;; Name: ;;; students ;;; Type: ;;; Vector of student records ;;; Each record has form (lastname firstname box email gradyear major) ;;; Everything in that record is a string. (define students (vector (list "Arnold" "Abigail" "01-13" "ARNOLD" "2003" "UND") (list "Barnum" "Bruce" "01-37" "BARNUM" "2004" "UND") (list "Brown" "Ryan" "03-18" "BROWNR" "2003" "UND") (list "Cherry" "Jane" "02-50" "CHERRY" "2001" "GRM-WES") (list "Evans" "Samuel" "04-64" "EVANS" "2004" "UND") (list "Finnessy" "James" "04-75" "FINNESSY" "2004" "UND") (list "Griffin" "Emer" "06-62" "GRIFFINE "2003"" "UND") (list "Jamal" "Taha" "17-27" "JAMALTH" "2004" "UND") (list "Kmiec" "Angela" "07-27" "KMIEC" "2004" "UND") (list "Knoernschild" "Nathan" "07-01" "KNOERNSC" "2001" "ENG") (list "Koomjian" "Jonathan" "07-84" "KOOMJIAN" "2003" "UND") (list "Lieberman" "Rachel" "09-79" "LIEBERMA" "2001" "HIS") (list "Omvig" "Jacob" "10-02" "OMVIG" "2003" "UND") (list "Perng" "Annie" "10-73" "PERNG" "2004" "UND") (list "Pervaiz" "Ammar" "10-82" "PERVAIZA" "2004" "UND") (list "Pinchback" "Piper" "11-19" "PINCHBAC" "2004" "UND") (list "Rathsam" "Jonathan" "11-66" "RATHSAM" "2003" "UND") (list "Romanelli" "Marisa" "18-79" "ROMANELL" "2001" "MAT") (list "Runyowa" "Tsaurai" "11-86" "RUNYOWA" "2003" "UND") (list "Schneider" "Bevin" "18-83" "SCHNEIDB" "2003" "UND") (list "Sheikh" "Muhammad" "12-75" "SHEIKHMA" "2004" "UND") (list "Slagle" "Michael" "13-27" "SLAGLE" "2001" "REL") (list "Sohonie" "Nikhil" "13-31" "SOHONIE" "2001" "ECN") (list "Techavalitpongse" "Sylvia" "13-63" "TECHAVAL" "2003" "UND") (list "Vanderhyden" "Sam" "14-53" "VANDERHY" "2004" "UND") (list "Wagner" "Nicholas" "14-48" "WAGNER" "2002" "UND") (list "Walker" "Richard" "15-08" "WALKERRI" "2004" "UND") (list "Weiss" "Gregory" "14-43" "WEISSG" "2003" "UND") (list "Wellons" "Jonathan" "15-51" "WELLONS" "2004" "UND") (list "Zhang" "Yang" "15-83" "ZHANG" "2003" "UND"))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Procedures ;;; Procedure: ;;; linear-search-list ;;; Parameters: ;;; lst, a list ;;; pred?, predicate ;;; Purpose: ;;; Searches the list for a value that matches ;;; the predicate. ;;; Produces: ;;; A matching value, if one exists. ;;; #f, otherwise. ;;; Preconditions: ;;; The first parameter is a list. ;;; The second parameter is a unary predicate. ;;; Postconditions: ;;; If the procedure returns #f, no element of the ;;; list matches the predicate. ;;; If the procedure returns some other value, v, then ;;; (1) (pred? v) returns #t and (2) v is in lst. (define linear-search-list (lambda (pred? lst) (cond ; If the list is empty, no values match the predicate. ((null? lst) #f) ; If the predicate holds on the first value, use that one. ((pred? (car lst)) (car lst)) ; Otherwise, look at the rest of the list (else (linear-search-list pred? (cdr lst)))))) ;;; Procedure: ;;; linear-search-vector ;;; Parameters: ;;; vec, a vector ;;; pred?, predicate ;;; Purpose: ;;; Searches the vector for a value that matches ;;; the predicate. ;;; Produces: ;;; The index of the matching value, if there is one. ;;; #f, otherwise. ;;; Preconditions: ;;; The first parameter is a vector. ;;; The second parameter is a unary predicate. ;;; Postconditions: ;;; If the procedure returns #f, no element of the ;;; vector matches the predicate. ;;; If the procedure returns some other value, i, then ;;; (pred? (vector-ref vec i)) returns #t. (define linear-search-vector (lambda (pred? vec) ; Grab the length of the vector so that we don't have to ; keep recomputing it. (let ((len (vector-length vec))) ; Helper: Keeps track of the position we're looking at. (let kernel ((position 0)) ; Start at position 0 (cond ; If we've run out of elements, give up. ((= position len) #f) ; If the current element matches, use it. ((pred? (vector-ref vec position)) position) ; Otherwise, look in the rest of the vector. (else (kernel (+ position 1)))))))) ;;; Procedure: ;;; search-list-for-keyed-value ;;; Parameters: ;;; key, a key to search for. ;;; values, a list of compound values. ;;; get-key, a procedure that extracts a key from a compound value. ;;; Purpose: ;;; Finds a member of the list that has a matching key. ;;; Produces: ;;; A matching value, if found. ;;; #f, otherwise. ;;; Preconditions: ;;; The get-key procedure can be applied to each element of values. ;;; Postconditions: ;;; If the procedure returns #f, there is no value for which ;;; (equal? key (get-key val)) ;;; holds. Otherwise, returns some value for which that holds. (define search-list-for-keyed-value (lambda (key values get-key) (linear-search-list (lambda (val) (equal? key (get-key val))) values))) ;;; Procedure: ;;; binary-search ;;; Parameters: ;;; key, a key we're looking for ;;; vec, a vector to search ;;; get-key ;;; less-equal?, a binary predicate that tells us whether or not ;;; one key is less-than-or-equal-to another. ;;; Produces: ;;; The index of a value with key sought, if found. ;;; #f, otherwise. ;;; Preconditions: ;;; The vector is "sorted. That is, ;;; (less-equal? (get-key (vector-ref vec i)) ;;; (get-key (vector-ref vec (+ i 1)))) ;;; holds for all reasonable i. ;;; The less-equal? procedure can be applied to all pairs of keys ;;; in the vector (and to the supplied ot key) ;;; Postconditions: ;;; If the procedure returns #f, no element of the ;;; vector matches the predicate. ;;; If the procedure returns some other value, i, then ;;; the key of (vector-ref vec i) is equal to key. (define binary-search (lambda (key vec get-key less-equal?) ; Search a portion of the vector from lower-bound to upper-bound (let search-portion ((lower-bound 0) (upper-bound (vector-length vec))) (if (<= lower-bound upper-bound) (let* ((midpoint (quotient (+ lower-bound upper-bound) 2)) (middle-element (vector-ref vec midpoint)) (middle-key (get-key middle-element))) (cond ((not (less-equal? middle-key key)) (search-portion lower-bound (- midpoint 1))) ((not (less-equal? key middle-key)) (search-portion (+ midpoint 1) upper-bound)) (else midpoint))) #f))))