Find Maximum from a Tree - functional-programming

I am trying to find the maximum number from a given tree:
(define-struct (Some T)
([value : T]))
(define-type (Option T)
(U 'None (Some T)))
(define-type BST (U 'E Nd))
(define-struct Nd
([root : Integer]
[lsub : BST]
[rsub : BST]))
(: maxi : BST Integer -> Integer)
(define (maxi x acc)
(match x
('E acc)
((Nd ro ls rs)
(cond
((> ro acc) (maxi ls ro))
(else
(maxi rs acc))))))
The above quote does not work properly when I enter the following:
(maxi (Nd 1 (Nd 2 (Nd 4 (Nd 8 'E 'E) (Nd 9 'E 'E)) (Nd 5 'E 'E)) (Nd 3 (Nd 6 'E 'E) (Nd 7 'E 'E))) 0)
Can someone please help?
Thank you!

So here is your test:
(maxi
(Nd
1
(Nd 2
(Nd 4
(Nd 8 'E 'E)
(Nd 9 'E 'E))
(Nd 5 'E 'E))
(Nd 3
(Nd 6 'E 'E)
(Nd 7 'E 'E)))
0)
And here is what happens:
acc root what to do?
---------------------------------
0 1 go left with acc = root
1 2 idem
2 4 idem
4 8 idem
8 E return 8
If you expect your input trees to satisfy the binary search tree property, stating that values on the left subtree are always greater than root and values of the right subtree are all smaller or equal, then your test tree is a malformed BST, since 9 is greater than 4.
By the way, if you had a BST, where would the maximal value be located?
If however the tree is just a random tree, then you have to compute the maximum of both subtrees and the root value before being able to determine the overall maximal value.
Basically, you want to do:
(tree-max (Nd root left right)) = (max root
(tree-max left)
(tree-max right))
If you want to do it recursively, you will encounter a problem in the base case because you will have to provide a maximal value for an empty leaf node: any value you will pick will make your code incorrect for a tree which contains values strictly below that value. Say you choose zero and compute the max of a tree with only strictly negative numbers, then zero is the wrong answer because it does not appear in the tree (what could you do?).
You can choose to use an accumulator instead of recursion, but in that case you will need two accumuators: the maximum so far and the list of subtrees to visit next. Basically you replace the call stack with a heap-allocated stack.
I can't currently test the following code, but here is a possible implementation:
(define tree-max (tree greatest todo)
(match tree
('E greatest (if (null? todo)
greatest
(tree-max (first rest)
greatest
(rest todo))
((Nd root left right) (tree-max left
(max greatest root)
(cons right todo))))

Related

Scheme find far left node of a tree recursively

I am writing a function that finds the farthest left node in any tree. The function does not traverse the tree or give the farthest left node but just gives the left most child of the first node.
(define (far-left tree)
(cond (null? (cadr tree))
(car tree)
(far-left (cdr tree))))
sample input, which gives many nodes rather than the desired one:
(display (far-left '(1 (3 4 (6 7 (12 13))) 8 9 (10 11))))
What you call "the left most child of the first node" is (cadr tree).
There is one (cadr tree) in your function, and that suggests that the first condition is always true.
And that is what's happening.
cond's form is
(cond clause-1 clause-2 ...)
Each clause in turn has the form (condition value).
That is,
(cond (condition-1 value-1)
(condition-2 value-2)
(condition-3 value-3)
...)
If you match this to your function, you will see that
null? is condition-1 and (cadr tree) is value-1,
car is condition-2 and tree is value-2, and
far-left is condition-3 and (cdr tree) is value-3.
Since null? is not #f, the first clause is always selected.
The correct form is
(define (far-left tree)
(cond
((null? (cadr tree)) (car tree))
(else (far-left (cdr tree)))
This code still does not work, though.
Fixing the bugs left as an exercise.
Data Definition: Tree
A Tree is either a Leaf or a Node where:
A Leaf is a Number.
A Node is a non-empty list of sub-Trees .
Function: far-left
Condition 1: A Leaf as an input is invalid because we're supposed to find the "farthest left node in any tree.
Condition 2: If a Node has Leaf as its left-most (or first) element, then it is the left-most node. If the left-most element is a Tree that is not a Leaf we recur on it.
#lang typed/racket
(define-type Leaf Number)
(define-type Node (Pairof Tree (Listof Tree)))
(define-type Tree (U Leaf Node))
(: far-left (-> Tree Node))
(define (far-left tree)
(cond [(number? tree) (error "Farthest left node of a leaf does not exist!")]
[(cons? tree) (if (number? (first tree)) tree (far-left (first tree)))]))
Tests:
(far-left '(1 (3 4 (6 7 (12 13))) 8 9 (10 11)))
; => '(1 (3 4 (6 7 (12 13))) 8 9 (10 11))
(far-left '((3 4 (6 7 (12 13))) 1 8 9 (10 11)))
; => '(3 4 (6 7 (12 13)))
(far-left '(((6 7 (12 13)) 3 4) 1 8 9 (10 11)))
; => '(6 7 (12 13))
(far-left '((((12 13) 6 7) 3 4) 1 8 9 (10 11)))
; => '(12 13)

Representing an amount of money with specific bills

I want to write a function in Racket which takes an amount of money and a list of specific bill-values, and then returns a list with the amount of bills used of every type to make the given amount in total. For example (calc 415 (list 100 10 5 2 1)) should return '(4 1 1 0 0).
I tried it this way but this doesn't work :/ I think I haven't fully understood what you can / can't do with set! in Racket, to be honest.
(define (calc n xs)
(cond ((null? xs) (list))
((not (pair? xs))
(define y n)
(begin (set! n (- n (* xs (floor (/ n xs)))))
(list (floor (/ y xs))) ))
(else (append (calc n (car xs))
(calc n (cdr xs))))))
Your procedure does too much and you use mutation which is uneccesary. If you split the problem up.
(define (calc-one-bill n bill)
...)
;; test
(calc-one-bill 450 100) ; ==> 4
(calc-one-bill 450 50) ; ==> 9
Then you can make:
(define (calc-new-n n bill amount)
...)
(calc-new-n 450 100 4) ; ==> 50
(calc-new-n 450 50 9) ; ==> 0
Then you can reduce your original implememntation like this:
(define (calc n bills)
(if (null? bills)
(if (zero? n)
'()
(error "The unit needs to be the last element in the bills list"))
(let* ((bill (car bills))
(amount (calc-one-bill n bill)))
(cons amount
(calc (calc-new-n n bill amount)
(cdr bills))))))
This will always choose the solution with fewest bills, just as your version seems to do. Both versions requires that the last element in the bill passed is the unit 1. For a more complex method, that works with (calc 406 (list 100 10 5 2)) and that potentially can find all combinations of solutions, see Will's answer.
This problem calls for some straightforward recursive non-deterministic programming.
We start with a given amount, and a given list of bill denominations, with unlimited amounts of each bill, apparently (otherwise, it'd be a different problem).
At each point in time, we can either use the biggest bill, or not.
If we use it, the total sum lessens by the bill's value.
If the total is 0, we've got our solution!
If the total is negative, it is invalid, so we should abandon this path.
The code here will follow another answer of mine, which finds out the total amount of solutions (which are more than one, for your example as well). We will just have to mind the solutions themselves as well, whereas the code mentioned above only counted them.
We can code this one as a recursive-backtracking procedure, calling a callback with each successfully found solution from inside the deepest level of recursion (tantamount to the most deeply nested loop in the nested loops structure created with recursion, which is the essence of recursive backtracking):
(define (change sum bills callback)
(let loop ([sum sum] [sol '()] [bills bills]) ; "sol" for "solution"
(cond
((zero? sum) (callback sol)) ; process a solution found
((< sum 0) #f)
((null? bills) #f)
(else
(apply
(lambda (b . bs) ; the "loop":
;; 1. ; either use the first
(loop (- sum b) (cons b sol) bills) ; denomination,
;; 2. ; or,
(loop sum sol bs)) ; after backtracking, don't!
bills)))))
It is to be called through e.g. one of
;; construct `the-callback` for `solve` and call
;; (solve ...params the-callback)
;; where `the-callback` is an exit continuation
(define (first-solution solve . params)
(call/cc (lambda (return)
(apply solve (append params ; use `return` as
(list return)))))) ; the callback
(define (n-solutions n solve . params) ; n assumed an integer
(let ([res '()]) ; n <= 0 gets ALL solutions
(call/cc (lambda (break)
(apply solve (append params
(list (lambda (sol)
(set! res (cons sol res))
(set! n (- n 1))
(cond ((zero? n) (break)))))))))
(reverse res)))
Testing,
> (first-solution change 406 (list 100 10 5 2))
'(2 2 2 100 100 100 100)
> (n-solutions 7 change 415 (list 100 10 5 2 1))
'((5 10 100 100 100 100)
(1 2 2 10 100 100 100 100)
(1 1 1 2 10 100 100 100 100)
(1 1 1 1 1 10 100 100 100 100)
(5 5 5 100 100 100 100)
(1 2 2 5 5 100 100 100 100)
(1 1 1 2 5 5 100 100 100 100))
Regarding how this code is structured, cf. How to generate all the permutations of elements in a list one at a time in Lisp? It creates nested loops with the solution being accessible in the innermost loop's body.
Regarding how to code up a non-deterministic algorithm (making all possible choices at once) in a proper functional way, see How to do a powerset in DrRacket? and How to find partitions of a list in Scheme.
I solved it this way now :)
(define (calc n xs)
(define (calcAssist n xs usedBills)
(cond ((null? xs) usedBills)
((pair? xs)
(calcAssist (- n (* (car xs) (floor (/ n (car xs)))))
(cdr xs)
(append usedBills
(list (floor (/ n (car xs)))))))
(else
(if ((= (- n (* xs (floor (/ n xs)))) 0))
(append usedBills (list (floor (/ n xs))))
(display "No solution")))))
(calcAssist n xs (list)))
Testing:
> (calc 415 (list 100 10 5 2 1))
'(4 1 1 0 0)
I think this is the first program I wrote when learning FORTRAN! Here is a version which makes no bones about using everything Racket has to offer (or, at least, everything I know about). As such it's probably a terrible homework solution, and it's certainly prettier than the FORTRAN I wrote in 1984.
Note that this version doesn't search, so it will get remainders even when it does not need to. It never gets a remainder if the lowest denomination is 1, of course.
(define/contract (denominations-of amount denominations)
;; split amount into units of denominations, returning the split
;; in descending order of denomination, and any remainder (if there is
;; no 1 denomination there will generally be a remainder).
(-> natural-number/c (listof (integer-in 1 #f))
(values (listof natural-number/c) natural-number/c))
(let handle-one-denomination ([current amount]
[remaining-denominations (sort denominations >)]
[so-far '()])
;; handle a single denomination: current is the balance,
;; remaining-denominations is the denominations left (descending order)
;; so-far is the list of amounts of each denomination we've accumulated
;; so far, which is in ascending order of denomination
(if (null? remaining-denominations)
;; we are done: return the reversed accumulator and anything left over
(values (reverse so-far) current)
(match-let ([(cons first-denomination rest-of-the-denominations)
remaining-denominations])
(if (> first-denomination current)
;; if the first denomination is more than the balance, just
;; accumulate a 0 for it and loop on the rest
(handle-one-denomination current rest-of-the-denominations
(cons 0 so-far))
;; otherwise work out how much of it we need and how much is left
(let-values ([(q r)
(quotient/remainder current first-denomination)])
;; and loop on the remainder accumulating the number of bills
;; we needed
(handle-one-denomination r rest-of-the-denominations
(cons q so-far))))))))

List of Leaves in Racket

I am trying to create a list of leaves of a tree in Racket.
(define-struct (Some T)
([value : T]))
(define-type (Option T)
(U 'None (Some T)))
(define-type BST (U 'E Nd))
(define-struct Nd
([root : Integer]
[lsub : BST]
[rsub : BST]))
(: leaves : BST -> (Listof Integer))
;; return the list of leaves from left to right
;; note: the result must be strictly ascending
(define (leaves x)
(match x
('E '())
((Nd ro 'E 'E) (list ro))
((Nd ro ls rs)
(append (leaves ls) (leaves rs)))))
The above function however does not work. I get a list of all the leaves but its not ascending. Can someone please help?
I am learning to code at home so don't have access to teachers or mentors.

list to tree in typedracket

I am trying to convert a list of integers to a tree.
The following are my function definitions:
(define-struct (Some T)
([value : T]))
(define-type (Option T)
(U 'None (Some T)))
(define-type BST (U 'E Nd))
(define-struct Nd
([root : Integer]
[lsub : BST]
[rsub : BST]))
(: bst-from-list ((Listof Integer) -> BST))
;; build a BST from a list of integers: use foldl to do s
(define (bst-from-list x)
(cond
('() 'E)
((cons hd _) (Nd hd 'E 'E))
(else
(foldl
I am learning from home and have no idea what to do after foldl. Can someone please help me?>
You already have an (: insert : Integer BST -> BST) function.
To build a tree with the elements 1, 2, 3, using insert you could write
(insert 3 (insert 2 (insert 1 'E)))
This is a left fold over (1 2 3) with insert as the function and 'E as the initial value.
A left fold combines the first element with the initial value and then combines the result of that with the second element, and so on.
So all you need is
(: bst-from-list : ((Listof Integer) -> BST))
(define (bst-from-list ls)
(foldl insert 'E ls))

Insert Node into a Tree - Racket

I am trying to add a new node to the tree. The following are my definitions and function type:
(define-struct (Some T)
([value : T]))
(define-type (Option T)
(U 'None (Some T)))
(define-type BST (U 'E Nd))
(define-struct Nd
([root : Integer]
[lsub : BST]
[rsub : BST]))
(: insert : Integer BST -> BST)
;; insert an item into a tree
;; note: do not insert duplicate items
(define (insert n x)
(match x
('E 'E)
((Nd ro ls rs)
(cond
((= (size x) 1) (Nd ro (Nd n 'E 'E) 'E))
(else
(Nd ro ls rs))))))
Insert is the insert that will insert the node into the tree.
The following is the command that I will give:
(insert 10 (Nd 1 (Nd 2 (Nd 4 'E 'E) (Nd 5 'E 'E)) (Nd 3 (Nd 6 'E 'E) (Nd 7 'E 'E))))
And it should insert ten into the tree. However, I am learning independently at home and I have NO idea what to do. Please help. Thank you so much!
You're missing the recursion, and your base case is wrong.
Inserting in an empty tree creates a tree with one node.
Inserting in a non-empty BST has three cases:
If the item is the same as in this node, return the tree unchanged
If the item is smaller than this node, insert in the left subtree
Otherwise, insert in the right subtree
Something like
(define (insert n x)
(match x
('E (Nd n 'E 'E))
((Nd ro ls rs)
(cond
((= n ro) x)
((< n ro) (Nd ro (insert n ls) rs))
(else (Nd ro ls (insert n rs)))))))
The tree you're aiming to insert in isn't a BST though, so this won't work.
Your tree has the following structure:
1
/\
2 3
/\ /\
4 5 6 7
A search tree with those elements would look like this:
4
/\
2 6
/\ /\
1 3 5 7
which is
(Nd 4 (Nd 2 (Nd 1 'E 'E) (Nd 3 'E 'E)) (Nd 6 (Nd 5 'E 'E) (Nd 7 'E 'E)))

Resources