Binary trees in scheme - scheme

How would I count how many nodes a tree has?
;;; A Binary is one of:
;;; - Number
;;; - (make-node BT BT)
(define-struct node (left right))
(define tree1 (make-node (make-node 10 9)
(make-node 3
(make-node 1 5))))
(define (how-many? nd)
(cond
[(number? nd)....]
[(node? n)
(..... (how-many? (node-left nd))
(how-many? (node-right nd)))]))
so for tree1 I should get
(check-expect (how-many? tree1) 5)
I think I got the template right. If it's a number, you should return 1. But if it's a node, what type of function should I put in the dotted lines?

This is somewhat similar to how you'd process a list. The difference? that now you'll go to the "left" and to the "right" of each node, instead of going just to the "rest". Other than that, the same ideas apply:
(define (how-many? nd)
(cond
[(number? nd) <???>] ; if it's a leaf, then how many numbers does it have?
[(node? nd)
(<???> (how-many? (node-left nd)) ; how do we combine the results?
(how-many? (node-right nd)))]))
You got the base case right, as I can see in the question. The recursive case is simple! remember, how did we combine the results when we were adding the elements in a list? here's the same thing, it's just that we combine the results from the left and from the right subtrees.

Related

Scheme Binary Search Tree Adding Elements

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.

how do you sum tree in scheme

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

scheme consumes BT tree and returns the elements of the tree as a list of strings

You are provided with the following definition for binary tries
(define-struct leaf ())
;; interpretation: represents a leaf on a BT, a node with no children
(define-struct node (word left right))
;; interpretation: represents a node on a BT with a word, a left and a right
;; subtree
;; A BinaryTree (BT) is one of
;; - (make-leaf)
;; - (make-node String BT BT)
Design the program bt->los that consumes a BT tree and returns the elements of the tree as a list of strings. At each node your function should
1.process the left sub tree
2.process the word at this node
3.process the right sub tree
;; bt->los: tree -> los
;; consumes a BT tree and returns the elements of the tree as a list of strings.
(define (bt->los tree)
(cond
[(leaf? tree) ""]
[(node? tree)
(append (bt->los(list (node-left tree)))
(list (node-word tree))
(bt->los (list (node-right tree))))]))
I'm stuck here. Should have missed something. Don't we need recursion here?
Output should be like,
(define bt-abc (make-node "b"
(make-node "a" (make-leaf) (make-leaf))
(make-node "c" (make-leaf) (make-leaf))))
(bt->los bt-abc) (cons "a" (cons "b" (cons "c" empty)))
You are very close here. Just a couple of mistakes.
(define (bt->los tree)
(cond
[(leaf? tree) empty]
[(node? tree)
(append (bt->los (node-left tree))
(list (node-word tree))
(bt->los (node-right tree)))]))
First, you are constructing a list of string. Because it is a list, your base case should be empty. not "". Second, each node, already represents a BT, there is no need to list it. And bt->los returns
a list. With this simple changes, it works as expected for you test case.

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

Binary Search Tree Scheme

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.

Resources