;; The first three lines of this file were inserted by DrRacket. They record metadata ;; about the language level of this file in a form that our tools can easily process. #reader(lib "htdp-intermediate-reader.ss" "lang")((modname main) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f () #f))) ; A MaybeTree is one of ; - (make-tree [Number MaybeTree MaybeTree]) (define-struct tree [n left right]) ; - 'end (define sprout (make-tree 0 'end 'end)) (define seedling (make-tree 5 sprout (make-tree 6 'end 'end))) (define sapling (make-tree 10 (make-tree 6 sprout 'end) (make-tree 12 'end 'end))) (define good-tree (make-tree 50 sapling (make-tree 100 'end 'end))) (define broke-tree (make-tree 5 good-tree good-tree)) (define deeply-broke-tree (make-tree 10 (make-tree 6 'end (make-tree 11 'end 'end)) (make-tree 12 'end 'end))) ; Tree t -> Bool ; Determines whether a Tree is a binary search tree. (define (bst? t) (local [; <2: U{Num, Sym}, Num, U{Num, Sym} → Bool ; Convenient form of greater than. Slightly hack. (define (<2 a b c) (cond [(and (symbol? a) (symbol? c)) #t] [(symbol? a) (< (- b 1) b c)] [(symbol? c) (< a b (+ b 1))] [else (< a b c)])) ; recurse: t: Tree, lower: Num, upper: Num → Bool ; Recursively checks left & right with lower & upper bounds. (define (recurse t lower upper) (cond [(symbol? t) (symbol=? t 'end)] [else (and (<2 lower (tree-n t) upper) (recurse (tree-left t) lower (tree-n t)) (recurse (tree-right t) (tree-n t) upper))]))] (recurse t 'quite-little 'very-big))) (check-expect (bst? sprout) #t) (check-expect (bst? sapling) #t) (check-expect (bst? good-tree) #t) (check-expect (bst? broke-tree) #f) (check-expect (bst? deeply-broke-tree) #f) ; A Trie is a [Node] ; A Node is a ; (make-node [String c Boolean e [Node] l]) ; and represents a prefix tree. 'c' represents the node character, 'e' is a ; flag for if the node marks the end of a word in the tree, and 'l' is the list ; of child nodes. (define-struct node [c e l]) (define example-trie (list (make-node "a" #t (list (make-node "n" #t (list (make-node "d" #t '()) (make-node "t" #t '()))))) (make-node "b" #f (list (make-node "e" #t (list (make-node "e" #t '()) (make-node "t" #t (list (make-node "t" #f (list (make-node "e" #f (list (make-node "r" #t '()))))))))))) (make-node "c" #f (list (make-node "a" #f (list (make-node "t" #t '()))))))) ; String w, Trie t -> Boolean ; Determines whether the given word is in the given Trie. (define (in-trie? w t) (local [(define ln (string-length w)) ; undernode?: l: [Node], i: [Index] → Bool ; Whether it's in the node's list of nodes. (define (undernode? l i) (cond [(empty? l) #f] [else (or (atnode? (first l) i) (undernode? (rest l) i))])) ; atnode?: n: Node, i: Index → Bool ; Check if node has the character at index i in the word, and continue down if it does. (define (atnode? n i) (if (>= i ln) #f (if (string=? (node-c n) (substring w i (+ i 1))) (if (= (+ i 1) ln) ; If we've hit the end of the word. (node-e n) (undernode? (node-l n) (+ i 1))) #f)))] (undernode? t 0))) (check-expect (in-trie? "cat" example-trie) #t) (check-expect (in-trie? "ca" example-trie) #f) (check-expect (in-trie? "catch" example-trie) #f) (check-expect (in-trie? "better" example-trie) #t) (check-expect (in-trie? "bee" example-trie) #t) (check-expect (in-trie? "beee" example-trie) #f) (check-expect (in-trie? "" example-trie) #f) ; [String] l -> Trie ; Generates the trie for a list of strings. (define (strie l) (local [; String w, Trie t -> Trie ; Adds word w to a Trie. (define (triadd w t) (local [; String c, String wrest, Trie t -> Trie ; Helper function to insert a chacater (and the rest of the word) to the Trie. (define (insert-char c wrest t) (cond [(empty? t) (list (make-node c ; Node character. (string=? wrest "") ; Mark whether Node's a word end. (if (string=? wrest "") ; If more left in the word, recurse. '() (triadd wrest '()))))] [(string=? (node-c (first t)) c) ; Character matches -- return existing Trie Node + whatever added if necessary. (cons (make-node c (or (node-e (first t)) (string=? wrest "")) (if (string=? wrest "") (node-l (first t)) (triadd wrest (node-l (first t))))) ; Recurse. (rest t))] [else (cons (first t) (insert-char c wrest (rest t)))]))] (insert-char (substring w 0 1) (substring w 1) t)))] (foldl triadd '() l))) (check-expect (strie '("and" "bee" "cat" "an" "a" "ant" "better" "bet" "be")) example-trie)