;; A [BT X] is one of
;; - 'leaf
;; - (make-node X [BT X] [BT X])
(define-struct node (val left right))
;; interpretation: represents a node with a value
;; a left and right subtree
(define (tree-sum tree)
(cond
[(symbol=? tree 'leaf) ...] ;; the value remains same
[(node? tree)
(+ (tree-sum (node-val tree))
(tree-sum (node-left tree))
(tree-sum (node-right tree)))]))
not quite sure if i'm on the right track.
Normally, A pair tree is either
a leaf (not a pair), or
a pair, whose car and cdr values are pair-trees.
recursive summing procedure will have to deal with these two cases:
a numbers, i.e., leaves of a tree of numbers, and
pairs, in which case it should sum the left and right subtrees, and add those sums together.
Therefore,
(define (pair-tree-sum pair-tree)
(cond
[(number? pair-tree)
pair-tree]
[else
(+ (pair-tree-sum (car pair-tree))
(pair-tree-sum (cdr pair-tree)))]))
You can split the function into two parts - one that converts the tree into a list of numbers, and another that just uses foldl with that list, and foldl has the advantage of automatically doing the summation as an accumulator.
(define (tree->list tree)
(if (pair? tree)
(append (tree->list (car tree))
(tree->list (cdr tree)))
(list tree)))
(define (tree-sum tree)
(foldl + 0 (tree->list tree)))
You first need to check if the tree is empty, then if its not a list, else you call the function sum to the car of the list, and add to the cdr of the list.
(define (sum tree)
(cond [(empty? tree) 0]
[(not (list? tree)) (if (number? tree) tree 0)]
[else (+ (sum (first tree)) (sum (rest tree)))]))
Related
To begin, I wanted to write a function that:
Takes in:
A list of natural numbers, (list 2 6 1 23...) that could have repeating elements called "lst"
A random binary search tree called "bst"
Outputs:
An updated binary tree that adds every number on the list to it
Code
(define (recurse-lst bst lst)
(cond [(empty? roster) empty]
[(empty? lst) empty]
[else (recurse-lst (bst-add bst (first lst)) (rest lst))]))
; helper function
(define (bst-add bst sublst)
(cond [(empty? bst) (make-node (first sublst) empty empty)]
[(< (first sublst) (node-key bst))
(make-node (node-key bst)
(bst-add (node-left bst) (first sublst))
(node-right bst))]
[else
(make-node (node-key bst) (node-left bst)
(bst-add (node-right bst) (first sublst)))]))
Problem
I'm currently trying to get this working for nested lists; for example (list (list 1) (list 2)...), with each sub-list only having one element in them. However, it seems that it does not work and (first sublst) in bst-add turns the sublst into a number, like (first 1).
I think I've had similar bugs in other pieces of code before, but I cannot recall when and what it was.
right now you have
(define (recurse-lst bst lst)
(cond [(empty? roster)
....
"lst".
"roster".
you need always to include your error messages in the posts on SO.
next. you call (bst-add bst (first lst)) so the second argument in that call is already a number. yet in the definition of bst-add you name second parameter as "sublst" and treat it as a list. no need to take first again. and in fact taking first of a number is an error.
im trying to find the max value in a tree, but I'm having trouble understanding the recursion part of it.
what I have so far
(define mytree '(10 (5(4(2 ()()) (22()())) (21(15()()) (23 ()()))) (11(6()())(13()()))))
(define (leaf mytree)
(and(null?(cadr mytree)) (null? (caddr mytree))))
(define (maxval mytree)
(if (null? mytree)
mytree
(max (leaf(maxval (cadr mytree))) (leaf(maxval (caddr mytree))))))
(maxval mytree)
I'm trying to make the leaf function go through every number in the tree until it gets to the bottom numbers, where it will find the greatest value.
Formatting
Indent code, align subtrees, add space
Name predicate with ? at the end
Use tree instead of mytree
Define abstractions (left-child, right-child instead of cadr-soups)
This is more readable:
(define mytree
'(10 (5 (4 (2 () ())
(22 () ()))
(21 (15 ()())
(23 ()())))
(11 (6 () ())
(13 () ()))))
(define (tree-value tree)
(car tree))
(define (left-child tree)
(cadr tree))
(define (right-child tree)
(caddr tree))
(define (leaf? tree)
(and (null? (left-child tree)
(null? (right-child tree))))
(define (maxval tree)
(if (null? tree)
'()
(max (leaf? (maxval (left-child tree)))
(leaf? (maxval (right-child tree))))))
Recursive algorithm
The maximum value of a tree (maxvalue tree) is the maximum value among:
the value associated with the tree: (tree-value tree)
the maximum value of its left subtree: (maxvalue (left-child tree))
the maximum value of its right subtree: (maxvalue (right-child tree))
The degenerate case (base case) where a tree has no child is to return the value associated with the tree.
Your current algorithm does not do that. In particular:
Why is the result of leaf? given to max?
Why don't you check the value rooted at current tree?
You should be able to translate the above in terms of code. This should look roughly like this (untested):
(define (maxval tree)
(if (leaf? tree)
(tree-value tree)
(max (tree-value tree)
(maxval (left-child tree))
(maxval (right-child tree)))))
Short version: you need a data definition, and test cases.
Your data definition should probably read
;; a binary tree is either:
;; -- <you fill in this part>, or
;; -- <you fill in this part too>
Then, you need test cases.
write a test case for both cases of your data definition.
This should answer your question for you.
(In general, the stepper can be helpful, but in this case, I think the problem starts earlier.)
I don't understand how I am getting a contract violation. It seems when I create a bst it doesnt make 2 empty lists it just has ().
This is my remove method:
;Returns the binary search tree representing bst after removing x where f and g are predicates as defined in bst-contains.
(define (bst-remove bst f g x)
;if empty return empty
(cond ((empty? bst) (bst-create-empty)))
;else if equal then check right if right is empty then pull from left
(cond ((g (car bst) x) (cond ((empty? (caddr bst)) (cond ((empty? (cadr bst)) (bst-create-empty))
(else (car(cadr bst)))))
;if right isnt empty then remove from left
(else(bst-create (bst-max-right (caddr bst)) (cadr bst) (bst-remove (caddr bst) f g (bst-max-right (caddr bst)))))))
(else (bst-create (car bst) (bst-remove (cadr bst) f g x) (bst-remove (caddr bst) f g x)))))
My bst-create and bst-create-empty:
;Returns an empty binary search tree.
(define (bst-create-empty)
'())
;Returns a binary search tree having the specified root value, with left-subtree left and right-subtree right.
(define (bst-create root left right)
(list root left right))
The code I give it is
(bst-remove (bst-create 5 (bst-create 6 (bst-create-empty) (bst-create-empty)) (bst-create 4 (bst-create-empty) (bst-create-empty))) < = 6)
The error i get is car: contract violation expected: pair? given: ()
You have got Scheme and especially cond all wrong. If you in a body of a procedure have two statements like:
(define (test lst)
first-expression
tail-expression)
It is obvious that the tail-expression will follow the evaluation and discarding of any result of the first-expression. Also unless first-expression has side effects it is dead code. Your cond expressions (cond ((empty? bst) (bst-create-empty))) is dead code since no matter what the outcome is it will never be a part of the result since Scheme will evaluate the second cond unconditionally. It does (car bst) which throws the error.
The correct way to have multiple returns are by one expression:
(cond
(test1 consequent1)
(test2 consequent2)
(test3 consequent3)
(else alternative))
Needless to say all the previous tests are negative so if test3 is true, then you know that test1 and test2 both had negative results. You also know that if consequent1 is evaluated no other terms or tests gets evaluated. It stops at the first prositive.
In you specific case the code could have looked like this:
(define (bst-remove bst f g x)
(cond ((empty? bst)
(bst-create-empty))
((not (g (car bst) x))
(bst-create (car bst) (bst-remove (cadr bst) f g x) (bst-remove (caddr bst) f g x)))
((not (empty? (caddr bst)))
(bst-create (bst-max-right (caddr bst)) (cadr bst) (bst-remove (caddr bst) f g (bst-max-right (caddr bst)))))
((empty? (cadr bst))
(bst-create-empty))
(else
(caadr bst))))
Using nested if works too, but it makes harder to read code just like your nested cond. Notice that I negated some of the tests since they only have one alternative but several tests in its consequent. By negating I could have one consequent and continue testing for the other cases in the same cond.
You refer to your second cond as an else if in your comment, but it's not an else-if, it's just an if. That is, you check the second condition even if the first one was true, in which case the car part of the condition causes this error.
To fix this, you should make both conditions part of a single cond, in which case it will actually act like an else if.
It looks like you've misunderstood cond, or possibly Scheme in general.
The result of a function application is the value of the last expression in the function's body (the only reason for having more than one is if you're doing something that has a side effect), and cond expressions are evaluated in exactly the same way as other Scheme expressions.
So the expression (cond ((empty? bst) (bst-create-empty))) does not return an empty tree, it is evaluated and produces an empty tree, and that tree is discarded.
Then evaluation continues with the next cond, which is a bad idea when the tree is empty.
A further problem is that the function should produce a tree, but (car (cadr bst)) wouldn't.
If you define a few useful accessor functions:
(define bst-value car)
(define bst-left cadr)
(define bst-right caddr)
then these lines are more obviously wrong:
(cond ((empty? (bst-left bst)) (bst-create-empty))
(else (bst-value (bst-left bst)))))
Fixing it, it becomes (reasonably) clear that the entire expression
(cond ((empty? (bst-left bst)) (bst-create-empty))
(else (bst-left bst))))
is equivalent to
(bst-left bst)
Now you have
(cond ((empty? (bst-right bst)) (bst-left bst))
( else make a tree...
But there's a lack of symmetry here; surely, if the left subtree is empty, the result should be the entire right subtree in a similar way.
So,
(cond ((empty? (bst-right bst)) (bst-left bst))
(empty? (bst-left bst)) (bst-right bst))
( else make a tree...
But now we can spot another problem: even in these cases, we need to recurse into the subtrees before we're done.
I'll digress here because too many accessor repetitions and conds makes code pretty unreadable.
Using a couple of lets (and getting rid of the unused f parameter), I ended up with this:
(define (bst-remove tree g x)
(if (empty? tree)
(bst-create-empty)
;; If the tree isn't empty, we need to recurse.
;; This work is identical for all the cases below, so
;; lift it up here.
(let ([new-left (bst-remove (bst-left tree) g x)]
[new-right (bst-remove (bst-right tree) g x)])
;; Build an appropriate tree with the new subtrees.
(if (g (bst-value tree) x)
(cond [(empty? new-left) new-right] ;; If either new subtree is empty,
[(empty? new-right) new-left] ;; use the other.
;; The complicated case. Get the new node value from the
;; right subtree and remove it from there before using it.
[else (let ([new-value (bst-max-right new-right)])
(bst-create new-value
new-left
(bst-remove new-right g new-value)))])
;; The straightforward case.
(bst-create (bst-value tree)
new-left
new-right)))))
I have a problem that I need to complete:
We can represent a nonempty binary tree by list (root left_subtree
right_subtree) and the empty tree by the empty list. Each binary
search tree with integer labels can be considered representing a set
of integers. Write a function which, given a set of integers S as a
bst and an integer x, returns both the set of all the integers less
than x and that of all the integers greater than x as bst’s. Use a
pair rather than a list to represent the resulting sets.
I'm very new to Scheme. I've built trees using SML as well as prolog, but can't seem to get a hold of what I need to do for Scheme. Could anyone help me out and guide me towards this goal? Is my tree suppose to just look like this?
(list value left right)
Yes, that's one way to define a tree. Just so long as you make a proper ADT and use it consistently, it shouldn't matter after you've defined it.
(define (make-tree root left right)
(list root left right))
(define (right tree)
(caddr tree))
(define (left tree)
(cadr tree))
(define (root tree)
(car tree))
(define (empty-tree? tree)
(null? tree))
(define empty-tree '())
(define (leaf? tree)
(and (empty-tree? (left tree)) (empty-tree? right tree)))
(define (split-tree-at tree x)
(let ((less ...)
(more ...))
(cons less more))
(define (in-tree-below-x tree x) ;;assuming a sorted tree
(cond ((empty-tree? tree) (empty-tree))
((>= (root tree) x)
(in-tree-below (left tree) x))
(else (make-tree (root tree)
(left tree)
(in-tree-below-x (right tree) x)))))
My friend and I are currently working on creating a Binary Search Tree in Scheme. We cannot get it to save what we have inserted. My professor said we are to use set-car! (cdr ( for the left subtree somehow, but I don't know where exactly to put it in. We are supposed to use set-car! (cddr ( for the right subtree also.
We have done all of this so far correctly, but we just need help making it save our inserted nodes.
Code:
(define make-empty-BST '())
;create function to see if BST is empty
(define (emptyBST? BST) (null? BST))
;make non-empty BST with explicit list implementation
(define (make-BST root left-subtree right-subtree)
(list root left-subtree right-subtree))
;helper get root function
(define (getRoot BST) (car BST))
;helper get left subtree function
(define (getLeftsubTree BST) (cadr BST)) ;(car (cdr tr))
;helper get right subtree function
(define (getRightsubTree BST) (caddr BST)) ;(car (cdr (cdr tr)))
;Checks to see if a leaf is empty
(define (emptyleaf? BST) (and (null? (getLeftsubTree BST)) (null? (getRightsubTree BST))))
;inserts an item into the BST
(define (BST-insert BST item)
(cond
((emptyBST? BST) ;if empty, create a new root with given item - use empty lists for left and right subtrees
(make-BST item make-empty-BST make-empty-BST))
((< item (getRoot BST)) ;if item less than root, add to left subtree
(make-BST (getRoot BST)
(BST-insert (getLeftsubTree BST) item) ;recursion
(getRightsubTree BST)))
((> item (getRoot BST))
(make-BST (getRoot BST)
(getLeftsubTree BST)
(BST-insert (getRightsubTree BST) item)))
(else BST))) ; it's already in BST, do nothing
Since this sounds like an assignment, I don't want to provide the exact code that you need, but I'll show two functions that could be said to replace the nth element of list. The first will be analogous to yours, in that it returns a new list and doesn't modify the input list. The second will modify the input list.
(define (replace-nth n element list)
;; return a new list like list, but whose
;; nth element is element
(if (= n 0)
(cons element (cdr list))
(cons (car list) (replace-nth (- n 1) element (cdr list)))))
(let ((l (list 1 2 3 4 5 6)))
(display (replace-nth 3 'x l)) ; prints (1 2 3 x 5 6)
(display l)) ; prints (1 2 3 4 5 6)
The first returns a new list, but doesn't modify the input list. It creates a new list using cons applied to part of the old list and some new value. This is similar to what you're doing when you insert by creating a new tree that has the new value. The tree that you've passed in won't have it, but the tree will.
(define (set-nth! n element list)
;; set the nth element of list to be element
(if (= n 0)
(set-car! list element)
(set-nth! (- n 1) element (cdr list))))
(let ((l (list 1 2 3 4 5 6)))
(display (set-nth! 4 'x l)) ; prints #<void>
(display l)) ; prints (1 2 3 4 x 6)
The second modifies the list that is passed to it. Its return value isn't quite so important, because the structure passed into it actually gets modified. This is more like what you'd want to do with your insert function. You need to recurse until you get to the correct node in the tree, and the set its left or right child to be a new tree containing just the new element.
You've provided 'get' procedures, why not start by providing a 'set' procedure? Doing so works towards completing your 'tree/node abstraction' and gives you a base set of functions to try to use in your 'insert' procedure.
(define (setLeftsubTree BST left)
(set-car! (cdr BST) left))
(define (setRightsubTree BST right)
(set-car! (cddr BST) right))
Now, in your insert code, when you want to 'go left' but there is no left, call setLeftsubTree with a newly created leaf node.