I can't seem to figure out how to delete an element from the BST. This is my code
(define remove (lambda (x t)
(if (< x (car t)) (list (car t) (remove x (cadr t)) (caddr t))
(if (> x (car t)) (list (car t) (cadr t) (remove x (caddr t)))
(if (not(and (null? (cadr t)) (null? (caddr t))))
(let ((r (minimum (caddr t)))) ((remove r t) (set-car! t r)))
(list '() (cadr t) (caddr t)))))))
Minimum returns the minimum value in the tree.
If I try to delete an element that's not a leaf, it goes into an infinite loop. How can I fix it?
I think your biggest problem lies in this section:
((remove r t) (set-car! t r))
You are removing r from t, but you should really be removing r from the right subtree of t. I'm not sure why you are using mutability/setting, either; I think it complicates things in what could easily be a non-side effecting function. I would try something like:
(list r (cadr t) (remove r (caddr t)))
I also have to admit that I'm a bit confused about your intent with the last line. What are you using the empty list for?
As an alternative, you can take a look here for the whole implementation of BST in scheme:
http://en.literateprograms.org/Binary_tree_(Scheme)
It is very well documented and would give you a bit of insight about the way you can structure the code to be easy to read and debug. Especially, it treats leaf and node (non-leaf) removals separately.
Related
I'm new to Scheme and Lisp in general, and upon learning I've stumbled upon a cryptic syntax used in local procedure binding:
(define mock
(lambda (s)
;; this is what I don't understand
(let splice ([l '()] [m (car s)] [r (cdr s)])
(append
(map (lambda (x) (cons m x)) r)
(if (null? r) '()
(splice (cons m l) (car r) (cdr r)))))))
It took me a while to grasp that splice is a scoped procedure with 3 arities. Rewriting this in an ML-esque style it seems to produce similar output:
(define mock2
(lambda (s)
;; define `splice` first
(define splice
(lambda (la lb lc)
(append
(map (lambda (x) (cons lb x)) lc)
(if (null? lc) '()
(splice (cons lb la) (car lc) (cdr lc))))))
;; bind `splice` and its arguments together and call it with them
(let ([sp splice] [l '()] [m (car s)] [r (cdr s)])
(splice l m r))))
The second version is a bit longer and somewhat look more imperative, but defining splice as a normal procedure inside the scope before binding it in parallel with the arguments (or just chuck them in as-is) and calling it looks saner.
Question is are these two versions replaceable? If yes, could you help explain the first version's syntax of binding local variables (l, m, and r) within the splice binding form?
Calling splice is like re-entering a loop, which is what it is there for. A tail call is a goto anyway. It is often named loop, instead of thinking up some special name for it.
"looks saner" is debatable, and actually with Schemers you'll lose this one, because this is a very popular Scheme construct, called "named let". It is usually re-written with letrec btw, if/when one wants to rewrite it, to understand it better. Internal define can be used as well, but then, why not use (define (mock s) ... in the first place.
So, the usual way to re-write this
(define mock ; or: (define (mock s) ...
(lambda (s)
(let splice ([l '()] [m (car s)] [r (cdr s)])
(append
(map (lambda (x) (cons m x)) r)
(if (null? r) '()
(splice (cons m l) (car r) (cdr r)))))))
is this:
(define mock
(lambda (s)
(letrec ([splice (lambda (l m r) ; or: (define (splice l m r) ...
(append
(map (lambda (x) (cons m x)) r)
(if (null? r) '()
(splice (cons m l) (car r) (cdr r)))))])
(splice '() (car s) (cdr s)))))
and writing it in the named let way saves one from having it defined in one place and called in another, potentially far away. A call enters its body from the start anyway, and named let better reflects that.
This is pretty self-explanatory. The transformation from one form to the other is purely syntactical, and both can be used interchangeably.
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 the following recursive function in Lisp
(defun f (item tree)
(when tree
(if (equal item (car tree)) tree
(if (and (listp (car tree))
(equal item (caar tree)))
(car tree)
(if (cdr tree)
(f item (cdr tree)))))))
This function receives a tree and an item to look for in its immediate leaves. If item is the car of any sublist, then it will return that sublist. That is,
(f 'c '(a b c)) => (c)
(f 'b '(a b c)) => (b c)
(f 'a '((a 1 2) b c)) => (a 1 2)
I've recently been informed that (Emacs Lisp) doesn't do tail recursion optimization, so I've been advised to turn this into a while loop. All of my training in Lisp has been in avoidance of loops like this. (I maintain that they are un-functional, but that's borderline pedantic.) I've made the following attempt for more conformative style:
(defun f (item tree)
(let ((p tree))
(while p
(cond
((equal item (car p)) p)
((and (listp (car p))
(equal item (caar p)))
(car tree))
(t (f item (cdr p))))
(setq p (cdr p)))))
I've shortened the function name for brevity/clarity, but do have a look at where it is being used if you are a power-user of emacs.
Your "iterative" solution is still recursing. It's also not returning the values found in the cond expression.
The following version sets a variable to the found result. Then the loop ends if a result has been found, so it can be returned.
(defun f (item tree)
(let ((p tree)
(result nil))
(while (and p (null result))
(cond ((equal item (car p)) (setq result p))
((and (listp (car p))
(equal item (caar p)))
(setq result (car tree)))
(t (setq p (cdr p)))))
result))
I was assigned to write a merge sort in Scheme but I have some issues with it. I showed it my professor and he said there is one simple mistake. Can someone help me?
Plzz!
(define msort
(lamdba(1st)
(cond
((null?? 1st) 1st)
((null? (cdr 1st)) 1st)
(#t ((letrec ((half (quotient (lenght 1st) 2))
(merge (lamdba (a b result)
(cond ((null? a) (apped (reserve a) result))
((null? b) (append (reserve a) result))
((> (car a) (car b) (merge a (cdr b) (cons (car b) result))
(#t (merge (cdr a) b (cons (car a) result)))))))
(merge (msort (take 1st half)) (msort (drop 1st half)) '()))))))
One simple mistake? He probably referred to #1, but even after fixing that you have some identifiers and parenthesis to fix:
lambda, null?, length, append, and reverse is spelled incorrectly.
letrec result gets applied since you have excess parenthesis around it.
cond in merge where you compare elements are missing parenthesis two places.
It's obvious you need help with parenthesis matching so you should download a decent IDE to write code in. I use DrRacket for Scheme development (#!R5RS, #!R6RS and #!racket) and it idents (just press CTRL+i to get it reidented after pasting in code) and indicate where function names are written wrong when you hit RUN.
Making merge a global function in the beginning and perhaps move it to a letrec later (if you have to) might ease development. Eg. you could find errors by testing stuff like (merge '(3 2 1) '()).
This is no guarantee the program will work since I only address syntax here. You need to debug it! DrRacket has a debugger too!
I think it is useful to implement first a function that allow to merge two ordered lists:
(define (merge l1 l2)
(if (empty? l1)
l2
(if (empty? l2)
l1
(if (< (car l1) (car l2))
(cons (car l1) (merge (cdr l1) l2))
(cons (car l2) (merge l1 (cdr l2)))))))
Now assume we have a function (get ls pos) capable to return the element of ls in position pos:
(define (get ls pos)
(if (= pos 1)
(car ls)
(get (cdr ls) (- pos 1))))
Finally, we can implement mergesort function:
(define (mergesort l p r)
(if (= p r)
(cons (get l p) empty)
(merge (mergesort l p (floor (/ (+ p r) 2))) (mergesort l (+ (floor (/ (+ p r) 2)) 1) r))))
I am a noob at Scheme. I have a binary search tree. The format of a node is a list of three elements, the first being the value at the node, the second being the left child node, and the third being the right child node. The "make" function creates an empty tree that looks like this: ( () () () ). I am able to create the tree, insert values, and find if a certain value exists in the tree. My problem comes when I try to write a function that returns the tree as an ordered list. Insert and Make functions:
;Inserts a number into the tree
(define (insert t x)
(cond ((null? (car t))
(list x (make) (make)))
((< x (car t))
(list (car t) (insert (cadr t) x) (caddr t)))
((> x (car t))
(list (car t) (cadr t) (insert (caddr t) x) ))
)
)
;Makes a new empty tree
(define (make)
(list (list) (list) (list))
)
Those works fine. Here is my as-list:
;Gives list of all numbers
(define (as-list t)
(cond
(
(null? (car t) )
(list)
)
(
#t
(append (as-list (cadr t)) (as-list (car t)) (as-list (caddr t)))
)
)
)
Running this, I get a contract violation, saying it expected "mpair?". I do not believe this is a logic error on my part, but it may be. Is this another parentheses problem?
Thank you for your time!
Your recursion should be
(append (as-list (cadr t)) (list (car t)) (as-list (caddr t)))
You only want to call as-list on trees, and the car of your t is not a tree.