Tree sorting function in Scheme - sorting

Im struggling with this problem for over 2 days now and still somehow I cannot solve it.
I have to write a function in SCHEME that takes a list in a tree and displays items in sorted order.
The way I define trees is '(6 (left... ) (right...))
My function to choose a tree:
(define (tree-sort tree)
(cond ((null? tree) '())
((> (car tree) (cadr tree))
(tree-sort (cadr tree)))
(else
(tree-sort (caddr tree))))
)
So I guess I should also have a function that sorts the most indepth list?
I really dont get it and this is the last time I will ever have to deal with scheme. I have never used stackoverflow so please excuse me if the formating is wrong.
Kindly thank you!

Now that you clarified that the tree is already sorted, then you're looking for an in-order traversal of the tree, which returns a sorted list of the elements - I'm assuming that you're interested in a list as the output, because of the base case shown in the question. Try something like this:
(define (tree-sort tree)
(if (empty-tree? tree)
'()
(append (tree-sort (left-subtree tree))
(list (value tree))
(tree-sort (right-subtree tree)))))
Use the appropriate procedures for testing if the tree is empty and for accessing each node's value, left and right subtrees. The above procedure will return a sorted list with the trees' values.

Related

recursion to find nulls

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.)

Confused about binary search trees (Scheme)

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)))))

How would I go about improving the efficiency (Scheme)?

I have this code:
(define tree `(A (B (C)) (D (E)) (C (E))))
(define (prog1 graph)
(let ([seen `()])
(define (sub g)
(cond
[(member (car g) seen) `()]
[else
(set! seen (cons (car g) seen))
(cond
[(null? (cdr g)) (list (car g))]
[else
(cons (car g) (map sub (cdr g)))])]))
(delete `() (sub graph))))
(define delete
(lambda (x y)
(if (null? y )
`()
(if (eqv? (car y) x)
(delete x (cdr y))
(cons (car y) (delete x (cdr y)))))))
It prints a connected graph where all the nodes appear once.
Running (prog1 tree)
prints: (A (B (C)) (D (E)))
I have looked at various depth-first searches in lisp (something which is similar to what I'm trying to do) and they appear to be much more elegant to this, some using iterative approaches. I am aware that the program isn't very efficient (on huge trees it runs pretty slow) so how would I go about improving the efficiency of this code?
Thanks, James
The member procedure performs an O(n) lookup on lists every time it's invoked. That's not what we want for quickly testing set membership, for that you should use a data structure providing an O(1) complexity for both adding elements and testing element membership in a collection, ideally a Set data structure or in its place a Hash Table. For example, in Racket try replacing these lines (or use the default hash table implementation in your Scheme interpreter):
(let ([seen `()]) => (let ([seen (make-hash)])
[(member (car g) seen) `()] => [(hash-has-key? seen (car g)) '()]
(set! seen (cons (car g) seen)) => (hash-set! seen (car g) 'ok)
Also, in general you want to use quotes in your code: '() instead of quasiquotes: `(), see the links to understand the difference and when it's appropriate to use quasiquoting.
Finally, you can use the built-in remove procedure, there's no need to implement your own delete.
In most cases the bottleneck in this code will not be the tree traversal, but the member lookup. The complexity of your function seems to be roughly O(M*N), where M is the number of distinct nodes and N is the number of total nodes. The reason why M goes into this as a factor is because you're looking up nodes in a linear list, which takes time proportional to the length of the list (which in your case is proportional to the number of distinct nodes).
The way to get rid of the M is to use a more efficient data structure for the lookup. R6RS defines hash tables, for instance.

Get the middle elements from List in scheme

I'm new to scheme , can someone please give me ideas on how to get , "the middle element from a list?"
Here's my solution. It's based on a tortoise-and-hare algorithm (which is used in any kind of list traversal where you need to detect circular lists), so it doesn't do any more work than a sane list traversal has to do anyway. :-)
(define (middle-elements lst)
(if (null? lst) '()
(let loop ((tortoise lst)
(hare (cdr lst)))
(cond ((eq? tortoise hare) #f)
((null? hare) (list (car tortoise)))
((null? (cdr hare)) (list (car tortoise) (cadr tortoise)))
(else (loop (cdr tortoise) (cddr hare)))))))
It covers the following cases:
If given an empty list, returns an empty list.
If given a list with an odd number of elements, returns a singleton list with the middle element.
If given a list with an even number of elements, returns a list with the two middle elements.
If given a circular list, returns #f.
If given an improper list (including a non-list), summons nasal demons.

Scheme binary search tree

I have already defined helper functions to be:
;; returns value of node
(define (value node)
(if (null? node) '()
(car node)))
;; returns left subtree of node
(define (left node)
(if (null? node) '()
(cadr node)))
;; returns right subtree of node
(define (right node)
(if (null? node) '()
(caddr node)))
and I am trying to write a function leaves that returns a list with the leaves of the tree in order of left to right.
(define (leaves tree)
(if (and (?null (left tree)) (?null (right tree)))
???
(leaves (left tree)) (leaves (right tree))))
but that is as far as I can get
ex: (leaves '(1 (2 () ()) (3 () ()))) should evaluate to '(2 3)
In what you have so far, the ??? is going to need to evaluate to the value of the leaf, ie. (value node) because it is the base case of your iteration. Also, you're going to need to combine the values you get back from the base case in your iteration case. list is usually a good first candidate to try when you need to combine multiple results cons is usually my second try. Taking those suggestions, your leaves function looks like this:
(define (leaves tree)
(if (and (null? (left tree)) (null? (right tree)))
(value tree)
(list (leaves (left tree)) (leaves (right tree)))))
which, when run on your sample of (leaves '(1 (2 () ()) (3 () ()))) does indeed evaluate to (2 3).
HOWEVER; YOU'RE NOT DONE! We're only testing with 1 level of recursion. What if we make a bigger tree? Something like: (leaves '(1 (2 (4 () ()) (5 () ())) (3 (6 () ()) (7 () ())))) Running this gives ((4 5) (6 7)). Those are the right values in the right order, but we have too much structure in there, too many parenthesis. This is a typical problem you will encounter throughout your scheme career, so let me explain why it happens, and how you can go about attacking the problem.
If look at the two branches of our if form, you'll notice that (value tree) returns an atom, or a number in this case. The else branch takes two of ??? and turns it into a list of ???. We're going to be executing the else branch multiple times - any time we're not in the base case. This means we're going to continue to wrap, and wrap, and wrap into a deeper and deeper list structure. So here's what we do about it.
Lets return a list in our base case, and keep our list flat in the recursion case. To return a list in our base case it is as simple as returning (list (value tree)) instead of just (value tree). In the recursion case, we need a function that takes 2 lists and combines them without making a deeper list. Such a function does exist - append. So let's look at what our leaves function looks like now:
(define (leaves tree)
(if (and (null? (left tree)) (null? (right tree)))
(list (value tree))
(append (leaves (left tree)) (leaves (right tree)))))
Intermezzo - Test cases
Racket has test suite library that has a very low barrier to entry called rackunit. Let's throw together a few quick test cases at the bottom of the file.
(require rackunit)
;;empty tree
(check-equal? (leaves '()) '())
;;simple balanced tree
(check-equal?
(leaves '(1 (2 () ()) (3 () ())))
'(2 3))
;;larger balanced tree
(check-equal?
(leaves '(1 (2 (4 () ()) (5 () ())) (3 (6 () ()) (7 () ()))))
'(4 5 6 7))
;;unbalanced tree
(check-equal?
(leaves '(1 (2 (4 () ()) ()) (3 () ())))
'(4 3))
Recently, racket has added support for submodules and specific support for test submodules if you are curious and want to look into them.
Back to our leaves problem. Running our tests, we notice our function doesn't behave well on unbalanced trees. We get extra ()s when we have a node that only has 1 leaf. That is because we are traversing both the left and the right subtrees whenever we're at a node that isn't a leaf. What we really need are two more cases in our if. We could nest the ifs, but scheme's cond form makes better sense.
Now, the template we're aiming to fill out is:
(define (leaves tree)
(cond [(leaf? tree) (...)]
[(and (has-left? tree) (has-right? tree))
(...)]
[(has-left? tree) (...)]
[(has-right? tree) (...)]
[else (error "should never get here")]))
I'll stop there in-case this is homework, and to give you the satisfaction of understanding and solving this the rest of the way. I hope my explanations have given you more direction that just "here's the code" answers.
Well this seems like you're doing Breadth First Search but with the alteration that you don't print yourself if you have two children (or just one, if you don't want to print nodes that only have one child).
I would aim for solving that first, and then changing your solution to that to solve this problem.
(define (list-of-leaves tree)
(if(leaf? tree)
(list (node tree))
(cond((right-branch-only? tree)(list-of-leaves (right-branch tree)))
((left-branch-only? tree)(list-of-leaves (left-branch tree)))
(else(append (list-of-leaves (left-branch tree))
(list-of-leaves (right-branch tree)))))))

Resources