Apply function to tree structure in racket - data-structures

I'm trying to apply a function to a tree in the form of a Map but not sure how to exactly go about it. Here's my attempt..
(define-struct node (value left middle right)#:transparent)
(struct emptyNode () #:transparent) ; leaf node
(define T (node 1 (node 2 (node 5 (emptyNode) (emptyNode) (emptyNode)) (emptyNode) (emptyNode))
(node 3 (emptyNode) (node 6 (emptyNode) (node 8 (emptyNode) (emptyNode) (emptyNode)) (emptyNode)) (emptyNode))
(node 4 (emptyNode) (emptyNode) (node 7 (emptyNode) (emptyNode) (emptyNode)))))
; 1
; / | \
; 2 3 4
; / | \
; 5 6 7
; |
; 8
;f
; a function, f, used in MaptoTree
(define (f b)
(* b 2))
;MaptoTree
; takes a function, f, and a tree structure, tree, as parameters.
; it should then produce a new tree structure where f has been applied to each value in the original tree
(define (MaptoTree f T)
(if (pair? T)
((map (lambda (x) (MaptoTree f x)) (rest T)))
(f T)))
edit: removed question about converting struct to list

You must use the selectors for node, instead of pair?, rest, etc. We're using a struct to represent the tree, not a normal list.
After fixing that, we just have to traverse the tree applying the function on each value, building a new tree as we go - like this:
(define (MaptoTree f T)
(if (emptyNode? T)
(emptyNode)
(node (f (node-value T))
(MaptoTree f (node-left T))
(MaptoTree f (node-middle T))
(MaptoTree f (node-right T)))))

You could also use the data/lazytree package (disclosure: I'm the author) to accomplish this, specifically the tree-map utility.
First, define a function to get the children of a node:
(define (node-children t)
(list (node-left t)
(node-middle t)
(node-right t)))
Then, use it to create the tree representation:
(require data/lazytree)
(define t (make-tree node-children
T
#:with-data node-value
#:empty-pred emptyNode?))
You can now use tree-map to get the result:
(tree-map f t) ; => #<stream>
This returns a stream representing the resulting tree, which you could convert back to your original format if you need to:
(export-tree node
(tree-map f t)
#:empty-cons emptyNode)
=> (node 2
(node 4
(node 10
(emptyNode)
(emptyNode)
(emptyNode))
(emptyNode)
(emptyNode))
(node 6
(emptyNode)
(node 12
(emptyNode)
(node 16
(emptyNode)
(emptyNode)
(emptyNode))
(emptyNode))
(emptyNode))
(node 8
(emptyNode)
(emptyNode)
(node 14
(emptyNode)
(emptyNode)
(emptyNode))))

Related

Creating binary tree using Racket

'(6 (3 (2) (5)) (7 () (9))) is a sorted binary tree
Write a recursive function tree-insert that takes a tree and a number and returns the tree with the number inserted.
(tree-insert 8 '()) should return ‘(8)
(tree-insert 5 ‘(8)) should return ‘(8 (5))
(tree-insert 3 '(6 () (7))) should return '(6 (3) (7))
(tree-insert 4 '(6 (3) (7))) should return '(6 (3 () (4)) (7))
The first thing to do when dealing with a problem like this is to realise that programming as if conses were all there is is not a good idea: it makes for code which is hard to understand and hard to write. You are processing a sorted binary tree which happens to be represented as a tree of conses. So first of all write some abstractions. Unfortunately the representation of the tree is kind of irregular: (9) is the same as (9 ()) is the same as (9 () ()), and the question wants you to return the shortest version, so the abstractions need to cope with that.
Empty nodes, and the value of a node are easy:
(define empty-node '())
(define empty-node? null?)
(define node-value car)
getting the left and right elements of a node are fiddly and I have used Racket's nice match facility for this:
(define (node-left node)
(match node
[(or (list _ l)
(list _ l _))
l]
[(list _)
empty-node]))
(define (node-right node)
(match node
[(list _ _ r)
r]
[(or (list _ _)
(list _))
empty-node]))
And finally making a node also needs to deal with the annoying shorthand versions of nodes with empty children:
(define (make-node value (left empty-node) (right empty-node))
(if (empty-node? right)
(if (empty-node? left)
(list value)
(list value left))
(list value left right)))
Once we have these abstractions, then tree-insert becomes essentially trivial to write:
(define (tree-insert n node)
(cond
[(empty-node? node)
(make-node n)]
[(< n (node-value node))
(make-node (node-value node)
(tree-insert n (node-left node))
(node-right node))]
[else
(make-node (node-value node)
(node-left node)
(tree-insert n (node-right node)))]))
The design recipe for functions is:
data definition
stub, signature, purpose
examples/unit tests
template, plan
function definition, testing
From the example binary tree:
'(6 (3 (2) (5)) (7 () (9))) #| 6
/ \
3 \
/ \ \
2 5 7
/ \
9 |#
one could deduce the data definition:
a TreeOfNumber is one of:
- empty
- (list Number TreeOfNumber TreeOfNumber)
where all numbers in first TreeOfNumber <= Number, all in second >
A first example/test could be:
(check-expect (tree-insert 8 '()) '(8 () ()))
and stub with signature and purpose:
(define (tree-insert n ton) ;; Number TreeOfNumber -> TreeOfNumber
;; produce ton with n inserted at correct place
(list n '() '()))
So the function will have the form:
(define (tree-insert n ton) ;; Number TreeOfNumber -> TreeOfNumber
;; produce ton with n inserted at correct place
(cond
[(empty? ton) (list n '() '()) ]
[else ... (list ... ) ]))
Two more examples:
(check-expect (tree-insert 6 '(8 () ())) '(8 (6 () ()) () ) )
(check-expect (tree-insert 10 '(8 () ())) '(8 () (10 () ())) )
can be rewritten as:
(check-expect (tree-insert 6 '(8 () ())) (list 8 (tree-insert 6 '()) '() ) )
(check-expect (tree-insert 10 '(8 () ())) (list 8 '() (tree-insert 10 '()) ) )
which suggests how to complete the definition:
(define (tree-insert n ton) ;; Number TreeOfNumber -> TreeOfNumber
;; produce ton with n inserted at correct place
(cond
[(empty? ton) (list n '() '()) ]
[else
(if (<= n (first ton))
(list (first ton) (tree-insert n (second ton)) (third ton))
(list (first ton) (second ton) (tree-insert n (third ton)))) ]))
A few more tests:
(check-expect (tree-insert 5 '(8 (6 () ()) ())) '(8 (6 (5 () ()) ()) ()) )
(check-expect (tree-insert 6 '(8 (6 () ()) ())) '(8 (6 (6 () ()) ()) ()) )
(check-expect (tree-insert 7 '(8 (6 () ()) ())) '(8 (6 () (7 () ())) ()) )
(check-expect (tree-insert 8 '(8 (6 () ()) ())) '(8 (6 () (8 () ())) ()) )
(check-expect (tree-insert 9 '(8 (6 () ()) ())) '(8 (6 () ()) (9 () ())) )
But other examples in the question omit trailing empty trees,
so introduce a function to strip them:
(define (tree-trim ton) ;; TreeOfNumber -> TrimmedTree
;; produce ton with trailing emptys dropped
(cond
[(empty? ton) empty ]
[(and (empty? (second ton)) (empty? (third ton)))
(list (first ton)) ]
[(empty? (third ton))
(list (first ton) (tree-trim (second ton))) ]
[else
(list (first ton) (tree-trim (second ton)) (tree-trim (third ton))) ]))
(check-expect (tree-trim '(8 (6 () (7 () ())) ())) '(8 (6 () (7))) )
tree-insert could be wrapped by tree-trim to produce the examples in the question;
as another example of combining these functions, one could have:
(define (tree-insert-list lon ton) ;; ListOfNumber TreeOfNumber -> TrimmedTree
;; produce ton with elements of lon inserted, trailing emptys dropped
(cond
[(empty? lon) (tree-trim ton) ]
[else
(tree-insert-list (cdr lon) (tree-insert (car lon) ton)) ]))
(check-expect
(tree-insert-list '(22 25 7 16 8 34 67 7 32 17 8 4 5 3) '())
'(22 (7 (7 (4 (3) (5))) (16 (8 (8)) (17))) (25 () (34 (32) (67)))) )
Welcome to DrRacket, version 8.6 [cs].
Language: Beginning Student with List Abbreviations; memory limit: 128 MB.
All 12 tests passed!
>
(define (tree-insert element tree)
(cond ((empty? tree) (list element))
((and (>= element (car tree)) (empty? (cdr tree)))
(list (car tree) '() (list element)))
((>= element (car tree))
(list (car tree) (cadr tree) (tree-insert (caddr tree) element)))
((empty? (cdr tree))
(list (car tree) (list element)))
(else
(list (car tree) (tree-insert element (cadr tree)) (caddr tree)))))
> (tree-insert 8 '())
'(8)
> (tree-insert 5 '(8))
'(8 (5))
> (tree-insert 3 '(6 () (7)))
'(6 (3) (7))
> (tree-insert 4 '(6 (3) (7)))
'(6 (3 () (4)) (7))

CPSed binary tree traversal doesn't work as expected

My recursive version looks like
(struct node (val left right) #:transparent)
(define t3 (node 3 '() '()))
(define t4 (node 4 '() '()))
(define t5 (node 5 '() '()))
(define t2 (node 2 t4 t5))
(define t1 (node 1 t2 t3))
;
; ----- 1 -----
; | |
; -- 2 -- 3
;| |
;4 5
(define (countv tree)
(if (null? tree)
0
(+ (node-val tree)
(countv (node-left tree))
(countv (node-right tree)))))
(countv t1)
And CPSed version
(define (countk tree k)
(if (null? tree)
(k 0)
(countk (node-left tree)
(λ (lval)
(countk (node-right tree)
(λ (rval)
(+ (node-val tree) lval rval)))))))
(countk t1 (λ (x) (node-val x)))
The result of countv was 15 as expected, while countk got 4.
You forgot to pass the recursive result to the continuation:
(define (countk tree k)
(if (null? tree)
(k 0)
(countk (node-left tree)
(λ (lval)
(countk (node-right tree)
(λ (rval)
(k (+ (node-val tree) lval rval))))))))
^
Here
Once you remember that, you'll get a runtime error since the result isn't a tree.
This didn't happen in your code because your initial continuation was never applied to anything.
You should call it like this instead:
(countk t1 (λ (x) x))

Find a list of items in a binary tree structures scheme

Write a function in Scheme that receives as argument of entry a binary search tree of instances of the student structure
, a list of birth years and returns a list of list of codes that indicate which birth dates are provided each year.
example:
This is the binary tree
(make-árbol-bin
(make-estudiante 5 "35889188" "Victor" (make-fecha 10 6 1991) "calle 67 con cra 20" "4444444") (make-
árbol-bin
(make-estudiante 2 "6457234" "Manuel" (make-fecha 12 10 1992) "calle 56 con cra 33" "5555555") (make-árbol-bin
(make-estudiante 1 "94252688" "Estela" (make-fecha 20 5 1993) "calle 4 con cra 2" "3333333") empty empty) empty)
(make-árbol-bin
(make-estudiante 7 "34987678" "Juan" (make-fecha 25 3 1995) "calle 34 con cra 12" "6666666") empty
empty)
)
List years
(list 1992 1991 )
It should return a list of lists of codes:
((list (list 2) (list 5) )
and I did this but I can not make me return the list of the list
(define-struct fecha ( dia mes año))
This is the structure of the student:
(define-struct estudiante ( codigo id nombre fechanaci direccion telefono))
This is the structure of the binary search tree:
(define-struct arbol-bin( estudiante nod-izq nod-der))
I did this
(define (elimina X L)
(if(null? L) '()
(if (equal? X (car L))
(elimina X (cdr L))
(cons (car L) (elimina X (cdr L))))))
(define (busca d tree)
(if (null? tree)
#f
(let ((node (arbol-bin-estudiante tree)))
(let ((n (estudiante-codigo node)))
(let ((fe (estudiante-fechanaci node)))
(if (or(equal? d (fecha-año fe))
(busca d (arbol-bin-nod-der tree)))
n
(busca d (arbol-bin-nod-izq tree))))))))
(define (pert lst tree)
(elimina false (map (lambda (d) (busca d tree)) lst)))
and this
(pert (list 1992 1991 ) tree)
return
(list 2 5)
As I can do to make me return this:
((list (list 2) (list 5) )
help me please!
You cannot make it return ((list (list 2) (list 5))), because that's not a correct Scheme expression. You can make it return (list (list 2) (list 5)) though:
> (list (list 2) (list 5))
'((2) (5))
To do so, in busca, just replace n with (list n):
(define (busca d tree)
(if (null? tree)
#f
(let ((node (árbol-bin-estudiante tree)))
(let ((n (estudiante-codigo node)))
(let ((fe (estudiante-fechanaci node)))
(if (or (equal? d (fecha-año fe))
(busca d (árbol-bin-nod-der tree)))
(list n) ; <------
(busca d (árbol-bin-nod-izq tree))))))))
or
> (list (list (list 2) (list 5)))
'(((2) (5)))
by changing the above line to (list (list n)).

Find a list in a binary tree scheme 2

Write a function in Scheme that receives as input argument list cedulas (identification) of students, a binary search tree with instances of the student structure and returns a list of instances of the student structure, where the identification of the list of students is in the binary search tree.
example:
This is the binary tree
(make-árbol-bin
(make-estudiante 5 "35889188" "Victor" (make-fecha 10 6 1991) "calle 67 con cra 20" "4444444") (make-
árbol-bin
(make-estudiante 2 "6457234" "Manuel" (make-fecha 12 10 1992) "calle 56 con cra 33" "5555555") (make-árbol-bin
(make-estudiante 1 "94252688" "Estela" (make-fecha 20 5 1993) "calle 4 con cra 2" "3333333") empty empty) empty)
(make-árbol-bin
(make-estudiante 7 "34987678" "Juan" (make-fecha 25 3 1995) "calle 34 con cra 12" "6666666") empty
empty)
)
List identification
(list "94252688" "94888888")
It should return the following list:
(list (make-estudiante 1 "94252688" "Estela" (make-fecha 20 5 1993) "calle 4 con cra 2" "3333333") )
and I did this but I can not make me return the list
(define-struct fecha ( dia mes año))
This is the structure of the student:
(define-struct estudiante ( codigo id nombre fechanaci direccion telefono))
This is the structure of the binary search tree:
(define-struct arbol-bin( estudiante nod-izq nod-der))
these are the functions that searches the list in the tree
(define(buscarevd n E)
(cond
[(or(empty? E) (empty? n))false]
[(equal? (first n)(estudiante-id E)) true]
[else (buscarevd (rest n) E)]))
(define(buscare n E)
(cond
[(empty? E)false]
[(< (car n)(estudiante-id E)) true]
[else false]))
(define (member-bt x bt)
(cond
[(empty? bt) false]
[(or(buscarevd x (arbol-bin-estudiante bt))
[else
(member-bt x (arbol-bin-nod-der bt))]))
and this
(member-bt (list "94252688" "94888888") tree)
return
true
As I can do to make me return the list.
Not sure if there is some kind of relationship between nodes which would permit you to skip sub-trees here, so I'd use this kind of approach:
(define (member-bt lst tree)
(let loop ((tree tree) (res '()))
(if (null? tree)
res
(let* ((node (árbol-bin-estudiante tree))
(res1 (loop (árbol-bin-nod-der tree) res))
(res2 (loop (árbol-bin-nod-izq tree) res1)))
(if (member (estudiante-id node) lst string=?)
(cons node res2)
res2)))))
then
(let ((lst '("94888888" "34987678" "94252688")))
(let ((res (member-bt lst tree)))
(values res (map estudiante-nombre res))))
=>
'(#<estudiante> #<estudiante>)
'("Estela" "Juan")
Note that this traverses the tree only once, but the order of the students in the result list is not the same as in the initial list. If order needs to be preserved you need to take a different approach, for example:
(define (member-bt-ordered lst tree)
(define (sub e tree)
(if (null? tree)
#f
(let ((node (árbol-bin-estudiante tree)))
(if (string=? e (estudiante-id node))
node
(or (sub e (árbol-bin-nod-der tree))
(sub e (árbol-bin-nod-izq tree)))))))
(filter values (map (lambda (e) (sub e tree)) lst)))
then
(let ((lst '( "94252688" "94888888" "35889188" "34987678" "6457234")))
(let ((res (member-bt-ordered lst tree)))
(values res (map estudiante-nombre res))))
=>
'(#<estudiante> #<estudiante> #<estudiante> #<estudiante>)
'("Estela" "Victor" "Juan" "Manuel")

Inorder traversal not working correctly

I am trying to write an inorder traversal without using append, here is my code
(define inorder
(lambda (tree)
(define inorder-iter
(lambda (tree list)
(if (empty-tree? tree)
list
(cons (inorder-iter (left-subtree tree)
(root tree)
(inorder-iter (right-subtree tree) list)))))
(inorder-iter tree '() )))
(define empty-tree? null?)
(define root car)
(define left-subtree cadr)
(define right-subtree caddr)
tree-1
(9
(6 (5 () ()) ())
(18 (11 () (13 () (17 () ()))) (65 (52 (41 (39 () ()) ()) ()) (99 () ()))))
When I call (inorder tree-1)
I get (((5 . 6) . 9) (11 13 17 . 18) (((39 . 41) . 52) . 65) 99) which looks absolutely terrible. What I am trying to get is '(5 6 9 11 13 17 18 39 41 52 65 99). What exactly am I doing wrong? Thank you!
You have several problems with your parentheses. Also notice that you're not using the list parameter - even more, it's poorly named, because it clashes with a built-in procedure.
The question requires that we don't use the built-in append function, but a simple cons won't work. Here's a possible solution:
(define inorder
(lambda (tree)
(define inorder-iter
(lambda (tree lst)
(if (empty-tree? tree)
lst
(inorder-iter (left-subtree tree)
(cons (root tree)
(inorder-iter (right-subtree tree)
lst))))))
(inorder-iter tree '())))
It works as expected:
(inorder tree-1)
=> '(5 6 9 11 13 17 18 39 41 52 65 99)

Resources