Buidling BST in racket from a list - scheme

I introduce today is to make a BST tree using a list. This is a list with sorted version, and strictly increasing, with no duplicates. like (list 100 200 300 400)..
Ialready write alot of code. It is here. but nothing is works..Can some one change it to fix?
Thank you
(define (bst-tree lst)
(cond
[(empty? lst) empty]
[else
(local [(define (pivot lst)
(cond
[(= 1 (length lst)) (first lst)]
[(= 2 (length lst)) (first lst)]
[else (pivot (rest (foldl cons empty (rest (foldl cons empty lst)))))]))
(define less (filter (lambda (x) (< x (pivot lst))) lst))
(define greater (filter (lambda (x) (> x (pivot lst))) lst))]
(append (make-node pivot (bst-tree less) (bst-tree greater))))]))

Here is the fix: (append (make-node(pivot lst)(bst-tree less) (bst-tree greater)))
pivot refers to the function, and therefore evaluates to a procedure applying it on the list gets the numeric value.

Related

Scheme: sort elements by pivot

I'm new to Scheme and to functional programming so please be gentle.
I'm trying to implement a function that takes a list and a pivot and return a list that contains the following 2 lists:
One for all elements that are less or equal to the pivot,
and one for all the elements that are greater than the pivot.
So I wrote the following code (EDITED (& WORKING) CODE - PROBLEM SOLVED):
define helper (lambda (lst pivot)
(define lst1 null)
(define lst2 null)
(define my-split (lambda (lst pivot lst1 lst2)
(if (null? lst)
(list lst1 lst2)
(if (<= (car lst) pivot)
(my-split (cdr lst) pivot (cons (car lst) lst1) lst2)
(my-split (cdr lst) pivot lst1 (cons (car lst) lst2))))))
(my-split lst pivot lst1 lst2)))
My current problem is that lst1 and lst2 are null at the end of the run so I guess the problem is with the lines (cons (car lst) lst1) & (cons (car lst) lst2))).
I saw some implementations on the web which use some complex commands that I'm not allowed to use (yes, it's homework).
Please offer ways to fix my code rather than offering your own.
Thanks
You correctly identified the two lines that are the main problem. cons just builds and returns a new list, whereas you're trying to mutate the variables lst1 and lst2. The correct way to do this is (set! lst1 (cons (car lst) lst1)) and (set! lst2 (cons (car lst) lst2)). Keep in mind, though, that good functional programming style avoids mutation. A good way to do that in this case would be to pass the two sub-lists as arguments as you recur down the main list, then return them when you get to the end.
Just like an expression like str.concat("hey") in Java doesn't change what str is (cons 1 lst1) doesn't change what lst1 is. It just returns a new value. Most of your function consist of dead code and if you really want to learn functional programming then altering bindings and objects are off limits.
You need to do something like this:
(define (count-odds lst)
(define (helper lst odds)
(cond ((null? lst)
odds)
((odd? (car lst))
(helper (cdr lst) (+ 1 odds)))
(else
(helper (cdr lst) odds))))
(helper lst 0))
(count-odds '(1 2 3))
; ==> 2
We never alter odds, we just update what is sent to the next recursion. Since Scheme has tail call elimination this is just like updating the variable in a while loop without actual mutation.

Reversed output in tail recursion

(define (sqr-tail lst)
(define (helper lst res)
(if (null? lst)
res
(cond ((list? (car lst))
(helper (cdr lst)
(cons (helper (car lst) ())
result)))
(else (helper (cdr lst)
(cons (expt (car lst) 2) res))))))
(helper lst ()))
I have this tail recursion function in scheme which sqr every element in the list, but unfortunately the result is reversed to what I suppose to output.
for input :
> (sqr-tail (list 1 2 4 3 (list 1 2 (list 1)) 3 3))
the output :
< (9 9 ((1) 4 1) 9 16 4 1)
thanks.
This is something that is inherent in the way Lisp/Scheme lists work: because there are only really conses, the way to build up lists is backwards. So the common tail-recursive-loop-with-an-accumulator approach as you've used ends up building the result backwards. The simple answer to this is that you need to reverse the result when you return it, and in your case, since you are recursing (not tail-recursing) into nested lists as well you need to reverse them as well of course.
Here is a somewhat cleaned-up and error-protected version of your original function (note this was written in Racket -- it may not be quite legal Scheme, but it is close):
(define (square-nested-list/reversed l)
(define (snl-loop lt accum)
(cond [(null? lt)
accum]
[(cons? lt)
(let ([head (car lt)]
[tail (cdr lt)])
(cond [(list? head)
(snl-loop tail (cons (snl-loop head '())
accum))]
[(number? head)
(snl-loop tail (cons (* head head) accum))]
[else (error "mutant horror death")]))]
[else (error "mutant death horror")]))
(snl-loop l '()))
So to get the result forwards we need to reverse the accumulator when we return it. This is a very small change to the above function:
(define (square-nested-list/forward l)
(define (snl-loop lt accum)
(cond [(null? lt)
(reverse accum)]
[(cons? lt)
(let ([head (car lt)]
[tail (cdr lt)])
(cond [(list? head)
(snl-loop tail (cons (snl-loop head '())
accum))]
[(number? head)
(snl-loop tail (cons (* head head) accum))]
[else (error "mutant horror death")]))]
[else (error "mutant death horror")]))
(snl-loop l '()))
If you want to be annoyingly clever and purist you can now notice that the tail-recursive-loop-with-accumulator approach produces results in reverse, so the trivial case of it is, in fact, reverse:
(define (square-nested-list/forward/stupidly-purist l)
(define (rev l)
(define (rev-loop lt a)
(if (null? lt) a (rev-loop (cdr lt) (cons (car lt) a))))
(rev-loop l '()))
(define (snl-loop lt accum)
(cond [(null? lt)
(rev accum)]
[(cons? lt)
(let ([head (car lt)]
[tail (cdr lt)])
(cond [(list? head)
(snl-loop tail (cons (snl-loop head '())
accum))]
[(number? head)
(snl-loop tail (cons (* head head) accum))]
[else (error "mutant horror death")]))]
[else (error "mutant death horror")]))
(snl-loop l '()))
People who do this are generally just trying to score points on the internet though (there are even more stupidly pure approaches for which you get more points).
And here are the results of calling those three functions:
> (define test-data '((1 2 3) (4 5) 6))
> (displayln (square-nested-list/reversed test-data))
(36 (25 16) (9 4 1))
> (displayln (square-nested-list/forward test-data))
((1 4 9) (16 25) 36)
> (displayln (square-nested-list/forward/stupidly-purist test-data))
((1 4 9) (16 25) 36)
Some other approaches
One issue with this 'reverse the result' is that it involves walking the result to reverse it, and also making a copy of it. Once upon a time this was something that was a real problem, because machines had only a tiny amount of memory and were very slow. Indeed, if your lists are enormous it still is a problem. More commonly it is a problem which exists in the minds of people who either, like me, remember machines which were very slow and had only tiny memory, or whose minds have been damaged by languages which encourage you to behave as if you were using such machines ('C programmers know the cost of everything but the value of nothing').
One partial answer to this problem offered by older Lisps is a function which is like reverse but works destructively: it reverses a list in place, destroying the original structure. This function is called nreverse in Common Lisp. If it existed in Scheme it would be called reverse! I suppose.
A more complete answer is to build the list forwards in the first place. You do this by trickery involving keeping a reference to the final cons of the list, and repeatedly replacing its cdr with a new final cons whose car is the object you are collecting. If you want to do this without your code looking horrible you need to use a macro: the one I wrote (for Common Lisp, not Scheme) was called collecting as it collected lists forwards. There are many others. Note that this approach requires mutable conses and also is not clearly efficient in the presence of modern garbage collectors.
Macros like collecting still have their place I think: not because they make your code faster, but because they can make it clearer: if you want collect some results into a list, then do that, don't do this weird reversing thing.
You are almost there.
All you need to do is reverse the return value for each sublist:
(defun sqr-tail (lst)
(labels ((helper (lst res)
(cond ((null lst)
(reverse res))
((listp (car lst))
(helper (cdr lst)
(cons (helper (car lst) ())
res)))
(t (helper (cdr lst)
(cons (expt (car lst) 2) res))))))
(helper lst ())))
(sqr-tail (list 1 2 4 3 (list 1 2 (list 1)) 3 3))
==> (1 4 16 9 (1 4 (1)) 9 9)
or, in scheme:
(define (sqr-tail lst)
(define (helper lst res)
(cond ((null? lst)
(reverse res))
((list? (car lst))
(helper (cdr lst)
(cons (helper (car lst) ())
res)))
(else (helper (cdr lst)
(cons (expt (car lst) 2) res)))))
(helper lst ()))

How do I write a function in DrRacket ISL/Lambda that moves occurrences of certain items to the end of the list?

I'm trying to learn how to do this, and I know it involves stacks, but I can't wrap my head around it unless I see a function in action. We've been given this example of a function to create and I need some help. Here it is:
;leafpile takes a list and returns the result of pushing all
;occurrences of the symbol 'leaf to the end of the list
> (leafpile '(rock grass leaf leaf acorn leaf))
(list 'rock 'grass 'acorn 'leaf 'leaf 'leaf)
We can use a helper function but the function needs to be written in a way to minimize recursive passes
update (heres what I got so far)
(define (leafpile/help ls pile)
(local
[
(define (helper 2ls leafpile)
(cond
[(empty? 2ls) (filter ls 'leaf)]
[(equal? (first 2ls) 'leaf)
(cons (first 2ls) (helper (rest 2ls) leafpile))]
[else (helper (rest 2ls) leafpile)]))]
(helper ls pile)))
OK snow I have this:
(define (helper lsh)
(cond
[(empty? lsh) '()]
[(not(equal? (first lsh) 'leaf))
(cons (first lsh) (helper (rest lsh)))]
[else (helper (rest lsh))]))
(define (count-leaf ls)
(cond
[(empty? ls) 0]
[(not (equal? 'leaf (first ls))) (count-leaf (rest ls))]
[else (add1 (count-leaf (rest ls)))]))
(define (leafpile ls)
(append (helper ls) (make-list (count-leaf ls) 'leaf)))
but I need it in one simple function with the least recursive passes possible.
Here is the solution I came up with:
(define (leafpile lst)
(for/fold ([pile (filter (lambda (leaf?) (not (equal? leaf? 'leaf))) lst)])
([i (build-list (for/fold ([leaves 0])
([leaf? lst])
(if (equal? leaf? 'leaf)
(add1 leaves)
leaves)) values)])
(append pile '(leaf))))
How it works:
The main for/fold loop iterates over a list with a length of the number of leaves there are, and the 'collection value' is a list of all the elements in lst that aren't the symbol 'leaf (achieved by filter).
Sample input/output:
> (leaf-pile '(rock grass leaf leaf acorn leaf))
'(rock grass acorn leaf leaf leaf)
Really simple way to do this:
(define (leaf? v)
(eq? v 'leaf))
(define (leafpile lst)
(append (filter (compose not leaf?) lst)
(filter leaf? lst)))
It really doesn't need to be more to it unless you experience performance issues and I usually don't for small lists. I tend to think of lists with fewer than a million elements as small. The obvious recursive one that might not be faster:
(define (leafpile lst)
(local [(define (leafpile lst n) ; screaming for a named let here!
(cond
((null? lst) (make-list n 'leaf))
((leaf? (car lst)) (leafpile (cdr lst) (add1 n)))
(else (cons (car lst) (leafpile (cdr lst) n)))))]
(leafpile lst 0)))
A tail recursive one that accumulates non leaf values, counts leaf values and uses srfi/1 append-reverse! to produce the end result:
(require srfi/1)
(define (leafpile lst)
(local [(define (leafpile lst acc n) ; I'm still screaming
(cond
((null? lst) (append-reverse! acc (make-list n 'leaf)))
((leaf? (car lst)) (leafpile (cdr lst) acc (add1 n)))
(else (leafpile (cdr lst) (cons (car lst) acc) n))))]
(leafpile lst '() 0)))

Scheme quick-sort with filter

I need to write the function (quick-sort pred lst)
lst is the list of numbers to be sorted
pred is the predicate by which the list is ordered, the signature of this predicate is: (lambda (x y) …)
- (quick-sort < lst) will sort ascending (small to large)
- (quick-sort > lst) will sort descending (large to small)
- (quick-sort (lambda (x y) (< (car x) (car y))) lst) will sort a list
with inner lists according to the first element of the inner list, ascending.
I started with regular quick-sort:
(define (quick-sort lst)
(cond
((null? lst) '())
((= (length lst) 1) lst)
(else (append (quick-sort (filter (lambda (n) (< n (car lst))) lst))
(list (car lst))
(quick-sort (filter (lambda (n) (> n (car lst))) lst))))))
And now I'm trying to do this with pred:
(define (quick-sort pred lst)
(define (quick-sort-help lst)
(cond ((null? lst) ())
((= (length lst) 1) lst)
(else
(append (quick-sort-help (filter (lambda (n) (pred n (car lst))) lst))
(list (car lst))
(quick-sort-help (filter (lambda (n) (not(pred n (car lst)))) lst)))))) (quick-sort-help lst))
And I get an infinite recursion or something.
Can you help me solve this problem please?
Thanks!
First of you don't need the helper function quick-sort-help.
It recurs infinitely because you apply your helper function to lst instead cdr lst. In your regular quicksort you have (filter (lambda (n) (< n (car lst))) and (filter (lambda (n) (> n (car lst))). But then in the one with the predicate you have the problem that (not (pred ...) would cover the cases for <= and not < if the predicate is > and vice versa. So it gets stuck because the first element in the list is always equal with itself.
Here a correct quicksort:
(define (qsort f lst)
(if (null? lst)
null
(let ([pivot (car lst)])
(append (qsort f (filter (λ (n) (f n pivot)) (cdr lst)))
(list pivot)
(qsort f (filter (λ (n) (not (f n pivot))) (cdr lst)))))))

Can't figure out what is wrong with "sort"

I'm trying to find out the smallest difference between two number in a sorted list so I wirte
(define (smallest-dif lst)
(cond
[(empty? lst) empty]
[(empty? (rest lst)) (smallest-dif (rest lst))]
[else (first (sort (cons (-(second lst) (first lst)) (smallest-dif (rest lst))) <))]))
My example is: (smallest-dif '(5 500 505 600 650 10000))
but drracket tells me this:sort: contract violation
expected: list?
given: '(50 . 9350)
I dont know what's wrong with my code. If I take out "first", the program can run properly.
Can anyone help me? thx.
Let’s look at what this part of the code is doing:
(sort (cons (-(second lst) (first lst)) (smallest-dif (rest lst))) <)
Say your list is '(1 2 3). Let’s work out part of the evaluation by hand:
(sort (cons (- 2 1) (smallest-dif '(2 3))) <)
(sort (cons 1 (first (sort (cons (- 3 2) (smallest-dif '(2))) <))) <)
(sort (cons 1 (first (sort (cons 1 empty) <))) <)
(sort (cons 1 1) <)
It’s trying to sort a cons cell, not a list, which is the contract violation it’s complaining about.
The problem with your code is that it sorts and takes the first of every part of the list. You need to split them up into one that returns just the diffs and one that does the sorting and picking.
(define (diffs lst)
(cond
[(or (empty? lst) (empty? (rest lst))) empty]
[else (cons (- (second lst) (first lst)) (diffs (rest lst)))]))
Then you can make your smallest-dif that uses that procedure in order to pick the smallest either the way you did with sorting and picking the first or you may use min.

Resources