Tree map function in Scheme - recursion

I wrote 90% of a tree-map function in scheme, but I encountered a major problem that I am having trouble with. When I test my code with binary tree, all but the first node gets mapped properly. The first node drops out, and I can't seem to think of a way around this. Any advice here as would be appreciated.
(define (value tree)
(car tree))
(define (left tree)
(car (cdr tree)))
(define (right tree)
(car (cdr (cdr tree))))
(define (tree-map f T)
(cond ((null? T) '())
((and (null? (right T))(null? (left T))) '())
((and (null? (right T))(not (null? (left T))))
(make-tree (f (value(left T)))
(tree-map f (left T))
(right T)))
((and (null? (left T))(not (null? (right T))))
(make-tree (f (value(right T)))
(left T)
(tree-map f (right T))
))))

This code is really convoluted. First I don't see an else statement, and a pretty big case drop (if both branches are not null tress). Second why are you worrying if the left or right is null when you have a case already for null trees?
(define (tree-map f T)
(cond ((null? T) '())
(else (make-tree (f (value T))
(tree-map f (left T))
(tree-map f (right T))))))
Being a human compiler is no fun. All you've don with you leaf, empty-left, and empty-right cases is rewrite the same code, but manually drop in the '() where appropriate instead of relying on the function to do it for you.

It seems that there are a couple of errors:
If a leaf node is found, you aren't applying the function to that node
The case where a node has both subtrees is missing
The part where the function is applied is wrong
Try this with one of your samples, the question doesn't include all the necessary code to test it myself:
(define (tree-map f T)
; empty tree
(cond ((null? T)
'())
; leaf node
((and (null? (right T)) (null? (left T)))
(make-tree (f (value T)) '() '()))
; empty right subtree
((and (null? (right T)) (not (null? (left T))))
(make-tree (f (value T))
(tree-map f (left T))
'()))
; empty left subtree
((and (null? (left T)) (not (null? (right T))))
(make-tree (f (value T))
'()
(tree-map f (right T))))
; both subtrees are present
(else
(make-tree (f (value T))
(tree-map f (left T))
(tree-map f (right T))))))

Related

finding nodes at depth N in a tree with racket

I've written a piece of code which returns the nodes which are at depth N of a tree. The root is considered to be at depth 1.
#lang racket
(define (depth n tree) (
cond [(= n 1) (car tree)]
[(> n 1) (
cond [(and (null? (cadr tree)) (null? (caddr tree)))
(null)]
[(and (not (null? (cadr tree))) (null? (caddr tree)))
(cons (depth (- n 1) (cadr tree)) null)]
[(and (null? (cadr tree)) (not (null? (caddr tree))))
(cons (depth (- n 1) (caddr tree)) null)]
[(and (not (null? (cadr tree))) (not (null? (caddr tree))))
(cons (depth (- n 1) (cadr tree)) (depth (- n 1) (caddr tree)))]
)]
)
)
Which works fine for depth 1, 2 and 3.
(define sampleTree
`(A
(B
(D () ())
(E () ())
)
(C
()
(F
(G () ())
()
)
)
)
)
(depth 1 sampleTree)
(depth 2 sampleTree)
(depth 3 sampleTree)
gives
'A
'(B . C)
'((D . E) F)
But for some reason, this does not work for depth 4.
(depth 4 sampleTree)
application: not a procedure;
expected a procedure that can be applied to arguments
given: '()
I honestly have no idea why this happens. It seems like the null in the first branch of > n 1 is getting applied to something.
Any help on debugging this code is appreciated.
The problem is (null). null is bound to the value '(). Putting parentheses around it tries to apply it as a procedure.
> null
'()
> (null)
application: not a procedure;
expected a procedure that can be applied to arguments
given: '()
[,bt for context]
May I suggest the following code formatting:
(define (depth n tree)
(cond
[(= n 1) (car tree)]
[(> n 1)
(cond
[(and (null? (cadr tree)) (null? (caddr tree))) '()]
[(and (not (null? (cadr tree))) (null? (caddr tree)))
(cons (depth (- n 1) (cadr tree)) null)]
[(and (null? (cadr tree)) (not (null? (caddr tree))))
(cons (depth (- n 1) (caddr tree)) null)]
[(and (not (null? (cadr tree))) (not (null? (caddr tree))))
(cons (depth (- n 1) (cadr tree)) (depth (- n 1) (caddr tree)))])]))
You may also want to ask yourself what type of value depth should return. In your example output, 'A is a symbol, '(B . C) is a pair, and '((D . E) F) is a proper list (with a pair as the first element).
As Peter pointed out, your result, with all the improper pairs, is probably not what you want - a proper list of values makes more sense. Here's a version that gives that, by using list and append instead of cons:
#lang racket/base
(require racket/list) ; For first, second, etc.
;;; Use functions to access parts of the tree structure to be clearer about what's being looked at
;;; and to make it easier to change to a struct or other more efficient implementation.
(define (node-value node)
(first node))
(define (node-left-child node)
(second node))
(define (node-right-child node)
(third node))
(define (depth desired-depth head)
(cond
((= desired-depth 1)
(list (node-value head)))
((> desired-depth 1)
(append (if (null? (node-left-child head)) '() (depth (- desired-depth 1) (node-left-child head)))
(if (null? (node-right-child head)) '() (depth (- desired-depth 1) (node-right-child head)))))))
(define sampleTree
'(A
(B
(D () ())
(E () ()))
(C
()
(F
(G () ())
()))))
(depth 1 sampleTree) ; '(A)
(depth 2 sampleTree) ; '(B C)
(depth 3 sampleTree) ; '(D E F)
(depth 4 sampleTree) ; '(G)

Why does List function call return runtime error in Scheme?

Getting an error for my binary search tree that I created in scheme.
$gosh main.sc
*** ERROR: list required, but got 5
Stack Trace:
_______________________________________
This is my code. I think the error has to do with how I am calling the functions, but I am not sure what exactly is wrong. I am calling the insert function with the two required parameters: tree, and a value of 5.
(define (member? t v)
(cond
((null? t)
#f
)
((< node (car t))
(member? (cadr t) v))
((> node (car t))
(member? (caddr t) v))
(else
#t
)
)
)
(define (insert t v)
(cond
((null? t)
(list v '() '())
)
((< v (car t))
(list (car t) (insert (cadr t) v) (caddr t))
)
((>= v (car t))
(list (car t) (cadr t) (insert (caddr t) v))
)
(else
t
)
)
)
(define (fold func val lst)
(if (null? lst) val (fold func (func val (car lst)) (cdr lst))))
(define (build lst)
(fold (lambda (t v) (insert t v)) '() lst))
(define t (list 10 '() '()))
(insert t 5)
display (member t 5)
display t
You care calling (member t 5) which is the same as (member '(10 '() '()) 5). Now member is not the same as your defined member? since it has a different name. member is the core library that looks like this:
(define (member obj lst)
(cond ((null? lst) #f)
((equal? obj (car lst)) lst)
(else (member obj (cdr lst)))))
Your member? has the two parameters swapped so when you miswrote the name and used the report version member 5 is not null, then it will do (car 5) and that will fail miserably. The error message that 5 is not of the required type list is pretty decent. It might spell the beans that it was member that failed though.
Another thing. If you replace the call to member with a call to member? you hit more problems. You use a variable node that is not defined anywhere.
The indentation and placing of parentheses is not goo lisp style. Your code should be written like this:
;; node doesn't exist in OPs code, but my implementation doesn't like member? without it
(define node 5)
;; possible typo by using the variable node ?
(define (member? t v)
(cond
((null? t)
#f)
((< node (car t))
(member? (cadr t) v))
((> node (car t))
(member? (caddr t) v))
(else
#t)))
(define (insert t v)
(cond
((null? t)
(list v '() '()))
((< v (car t))
(list (car t) (insert (cadr t) v) (caddr t)))
((>= v (car t))
(list (car t) (cadr t) (insert (caddr t) v)))
(else
t)))
(define (fold func val lst)
(if (null? lst) val (fold func (func val (car lst)) (cdr lst))))
(define (build lst)
(fold (lambda (t v) (insert t v)) '() lst))
(define t (list 10 '() '()))
(insert t 5)
;; NB doesn't call a procedure, just evaluates it.
display
;; Here the arguments are the wrong order and you don't use memeber?
(member t 5)
;; NB doesn't call a procedure, just evaluates it.
display
t

Recursion on list of pairs in Scheme

I have tried many times but I still stuck in this problem, here is my input:
(define *graph*
'((a . 2) (b . 2) (c . 1) (e . 1) (f . 1)))
and I want the output to be like this: ((2 a b) (1 c e f))
Here is my code:
(define group-by-degree
(lambda (out-degree)
(if (null? (car (cdr out-degree)))
'done
(if (equal? (cdr (car out-degree)) (cdr (car (cdr out-degree))))
(list (cdr (car out-degree)) (append (car (car out-degree))))
(group-by-degree (cdr out-degree))))))
Can you please show me what I have done wrong cos the output of my code is (2 a). Then I think the idea of my code is correct.
Please help!!!
A very nice and elegant way to solve this problem, would be to use hash tables to keep track of the pairs found in the list. In this way we only need a single pass over the input list:
(define (group-by-degree lst)
(hash->list
(foldl (lambda (key ht)
(hash-update
ht
(cdr key)
(lambda (x) (cons (car key) x))
'()))
'#hash()
lst)))
The result will appear in a different order than the one shown in the question, but nevertheless it's correct:
(group-by-degree *graph*)
=> '((1 f e c) (2 b a))
If the order in the output list is a problem try this instead, it's less efficient than the previous answer, but the output will be identical to the one in the question:
(define (group-by-degree lst)
(reverse
(hash->list
(foldr (lambda (key ht)
(hash-update
ht
(cdr key)
(lambda (x) (cons (car key) x))
'()))
'#hash()
lst))))
(group-by-degree *graph*)
=> '((2 a b) (1 c e f))
I don't know why the lambda is necessary; you can directly define a function with (define (function arg1 arg2 ...) ...)
That aside, however, to put it briefly, the problen is that the cars and cdrs are messed up. I couldn't find a way to tweak your solution to work, but here is a working implementation:
; appends first element of pair into a sublist whose first element
; matches the second of the pair
(define (my-append new lst) ; new is a pair
(if (null? lst)
(list (list (cdr new) (car new)))
(if (equal? (car (car lst)) (cdr new))
(list (append (car lst) (list (car new))))
(append (list (car lst)) (my-append new (cdr lst)))
)
)
)
; parses through a list of pairs and appends them into the list
; according to my-append
(define (my-combine ind)
(if (null? ind)
'()
(my-append (car ind) (my-combine (cdr ind))))
)
; just a wrapper for my-combine, which evaluates the list backwards
; this sets the order right
(define (group-by-degree out-degree)
(my-combine (reverse out-degree)))

Preorder Notation in Scheme

Assume that my "map-diff" function works properly for the following code. I am wondering how to take an arithmetic parse tree and output it in preorder notation. I want to be able to use my "map-diff" function inside my "preorder" function, but I can't figure out how to go about doing this. Are my base cases here correct?
(define (make-tree value left right) (list value left right))
(define (value tree) (car tree))
(define (left tree) (cadr tree))
(define (right tree) (caddr tree))
(define (prepare x)
(cond ((number? x) (number->string x))
((char? x) (string x))))
(define x
(map-diff (lambda (x) (prepare x))
(list #\+
(list #\*
(list 3 '() '())
(list 9 '() '()))
(list #\+
(list #\/ (list 5 '() '()) '())
(list 4 '() '())))))
(define (preorder T)
(cond ((null? T) "")
((eq? (value T) "+")
(cons (value T) (cons (preorder (left T)) (preorder (right T)))))
((eq? (value T) "*")
(cons (value T) (cons (preorder (left T)) (preorder (right T)))))
((eq? (value T) "-")
(cons "-" (preorder (left T))))
((eq? (value T) "/")
(cons "/" (preorder (left T))))
(else (value T))))
(preorder x)
First , don't mix your ADT and primative types together. If you define an ADT stick with it thoughout the program. X should be defined in terms of make-tree rather than list). And make-tree rather than cons in preorder. The way you have it now your going to get a dotted list as output rather than a nice proper list form.
I'm not sure what your trying to do with prepare, casting things to strings to parse them is fairly unusual, considering lisps dynamic typing.
Anyways here is one possibility
(define (preorder T)
(let ((top (prepare (value T))))
(cond ((null? T) "")
((eq? top "+")
(cons top (cons (preorder (left T)) (preorder (right T)))))
((eq? top "*")
(cons top (cons (preorder (left T)) (preorder (right T)))))
((eq? top "-")
(cons "-" (preorder (left T))))
((eq? top "/")
(cons "/" (preorder (left T))))
(else top)))
;; helper
(define (list-ref-at n)
(lambda (l) (list-ref l n)))
;; node data type
(define (make-node value left right)
`(NODE ,value ,left ,right))
(define node-value (list-ref-at 1))
(define node-left (list-ref-at 2))
(define node-right (list-ref-at 3))
;; leaf data type (as special node)
(define (make-leaf value)
(make-node value '() '()))
(define (node-is-leaf? node)
(and (null? (node-left node))
(null? (node-right node))))
;; convert to list
(define (node->preorder-list node)
(if (node-is-leaf? node)
(node-value node)
(let ((v (node-value node))
(l (node-left node))
(r (node-right node)))
(assert (not (null? l)))
(if (null? r)
(list v (node->preorder-list l)) ; unop
(list v (node->preorder-list l) (node->preorder-list r)))))) ;binop
;; test
> (define x (make-node '* (make-node '+ (make-leaf 1) (make-leaf 2)) (make-leaf 10))
> (node->preorder-list x)
(* (+ 1 2) 10)
> (set! x (make-node '- x '()))
> (node->preorder-list x)
(- (* (+ 1 2) 10))

Deleting a Node in Scheme

I am trying to delete a node from a Binary Search Tree in scheme, but I am having trouble with the removing part of the code. How can I delete a node value without creating a new tree in scheme?
(define (delete-node v T)
(cond ((null? T) '())
((< v (value T))
(delete-node v (left T)))
((> v (value T))
(delete-node v (right T)))
(else
(cond ((and (null? (right T))(not (null? (left T)))) '())
;promote the (left T) to the node
;repeat
((and (null? (left T))(not (null? (right T)))) '())
;promote the (right T) to the node
;repeat
For deleting a node in-place, your tree would have to be mutable - meaning: that either the value, the right subtree or the left subtree of a node can be modified in-place with new values.
It's easier to just build a new tree while traversing it, but even so there are a couple of implementation choices that must be made. Here's a sketch of a solution:
(define (delete-node v T)
(cond ((null? T) '())
((< v (value T))
; see how we build the new tree
(make-node (value T)
(delete-node v (left T))
(right T)))
((> v (value T))
; see how we build the new tree
(make-node (value T)
(left T)
(delete-node v (right T))))
(else
(cond ((and (null? (right T)) (and (null? (left T))))
; this case was missing
'())
((and (null? (right T)) (not (null? (left T))))
(left tree))
((and (null? (left T)) (not (null? (right T))))
(right tree))
(else
; implementation detail: if both subtrees of the
; node to be deleted are non-null, who should take
; the place of the deleted node? the new subtree
; must preserve the order property of the tree
<???>)))))
The interesting case is marked with <???>. There are several options, it's up to you to pick and implement one. For instance, in a sorted tree (which I assume is the case here), one could pick the biggest element from the left subtree, and recursively delete it before moving it into place.
Notice that if the tree has to remain balanced after deleting the node (according to the balancing definition in use), the algorithm is trickier - I'm assuming that the tree is not balanced.

Resources