(fixing a code for) racket-- deleting a node from a tree - racket

So I'm currently stuck in the intermediate level of racket, and have looked at various codes, but most of them I can't figure out
I'm trying to delete a node from a binary search tree
So, I've so far come up with this, which includes an empty node and the first and final node in the wrong order
(define-struct node (key value left right))
(define (delete bst k)
(local [(define empty-l (empty? (node-left bst)))
(define empty-r (empty? (node-right bst)))
(define full-l (not empty-l))
(define full-r (not empty-r))]
(local [(define (replace bst)
;;takes node and takes it away, finding the next part that should take over its spot
(cond
[(empty? bst) empty]
[(and empty-l empty-r) empty]
[(and empty-l full-r) (node-right bst)]
[(and full-l empty-r) (node-left bst)]
[(and full-l full-r) (make-node
(if (**empty? (node-right bst)) "MAKE_THIS_KEY_GO_AWAY"** (node-key (node-right bst)))
(if (**empty? (node-right bst)) "MAKE_THIS_VALUE_GO_AWAY"** (node-value (node-right bst)))
;(node-value (node-right bst))
(node-left bst)
(replace (node-right bst)))]))]
;(local ((define (find k bst)
;;if finds k, puts it through replace to replace it
(cond
[(empty? bst) empty]
[(= k (node-key bst)) (replace bst)]
[(< k (node-key bst)) (make-node (node-key bst)
(node-value bst)
(delete k (node-left bst))
(node-right bst))]
[else (make-node (node-key bst)
(node-value bst)
(node-left bst)
(delete k (node-right bst)))]))))
;; Example binary search tree for check-expect
(define t (make-node 5 "" (make-node 3 "" (make-node 2 "" (make-node 1 "" empty empty)
empty)
(make-node 4 "" empty empty))
(make-node 7 "" (make-node 6 "" empty empty) empty)))
(check-expect (delete t 5)
(**make-node 6 ""** (make-node 3 "" (make-node 2 "" (make-node 1 "" empty empty)
empty)
(make-node 4 "" empty empty))
(**make-node 7 ""** empty empty)))
;;What I actually get
(**make-node
7
""**
(make-node
3
""
(make-node
2
""
(make-node 1 "" empty empty)
empty)
(make-node 4 "" empty empty))
(**make-node
"MAKE_THIS_KEY_GO_AWAY"
"MAKE_THIS_VALUE_GO_AWAY"**
(**make-node 6 ""** empty empty)
empty))

The (full-l full-r) case is all messed up. To handle that case, you need to pick either what Wikipedia calls the "in-order predecessor" or the "in-order successor" of the instance of bst being handled by replace, then delete that key from replace's bst and make it be the replacement. These functions can be used to find the in-order predecessor/successor:
(define (in-order-predecessor tree)
(right-bottom (node-left tree)))
(define (in-order-successor tree)
(left-bottom (node-right tree)))
(define (left-bottom tree)
(if (empty? (node-left tree))
tree
(left-bottom (node-left tree))))
(define (right-bottom tree)
(if (empty? (node-right tree))
tree
(right-bottom (node-right tree))))
So you'd do something like this:
[(and full-l full-r)
(local [(define successor (in-order-successor bst))
(define old-right (node-right bst))
(define new-right (delete old-right (node-key successor)))]
(make-node (node-key successor) (node-value successor)
(node-left bst) new-right))]
Since this version of replace would no longer be recursive, it doesn't need to receive bst as an argument.
Also, you're getting the argument order of delete mixed up. You defined it as (delete node k) but in two places you call it as (delete k node).

Related

Create Python's collections.counter() method in Beginner Racket

The goal is to create a function that accepts a list of symbols and produces a list of key value pairs that count how many times each symbol in list appears. eg:
(counter (list 't 't 'c 'a)) -> (list (list 't 2) (list 'c 1) (list 'a 1))
The function must be completed with recursion
I've only gotten as far as to create a list of key value pairs that treat duplicates as standalone values:
(define val 0)
(define (counter los)
(cond
[(empty? los) empty]
[else (cons (list (first los) (add1 val))
(counter (rest los)))]))
(counter (list 't 't 'c 'a)) -> (list (list 't) (list 't) (list 'c 1) (list 'a 1))
It has been a very long time since I used BSL but I believe these operations are all present. There may be a cleaner way of doing this but I will leave it up to you to check the documentation and simplify it if possible
(define (counter los) (counter-helper los empty))
(define (counter-helper los lists)
(cond
[(empty? los) lists]
[else (if (list? (assq (first los) lists))
(counter-helper
(rest los)
(cons (list (first los) (add1 (second (assq (first los) lists))))
(remove (assq (first los) lists) lists)))
(counter-helper (rest los) (cons (list (first los) 1) lists)))]))
the if statement checks if there is already an entry in our list of lists for that key, it returns the pair if yes, false otherwise.
If the result is false we just append a new pair with value 1 and recur.
If it already exists, we construct a new pair from the previous one, with the same key, but the value incremented and append this new pair to our list of lists - the previous pair removed

DrRacket - update values in binary tree

I'm writing a function which produces a new version of a binary tree bt where each Node whose value is an odd length string, has its value replaced with the string "odd".
For example:
(check-expect (odd-length (make-node 4 "four"
(make-node 7 "seven"
empty
(make-node 2 "two" empty empty))
(make-node 32 "thirty-two" empty empty)))
(make-node 4 "four"
(make-node 7 "odd"
empty
(make-node 2 "odd" empty empty))
(make-node 32 "thirty-two" empty empty))
I've managed to write a function that converts a single value, but I don't know how to make it work for all nodes in the binary tree. Can anyone help? Thanks a lot ><
(define-struct node (key val left right))
(define (change-str bt)
(cond
[(= (remainder (string-length (node-val bt)) 2) 1)
(make-node (node-key bt) "odd" (node-left bt) (node-right bt))]
[(= (remainder (string-length (node-val bt)) 2) 0) bt]))
We can simply define a map over trees and pass change-str as a function over vals.
(define (odd-length tree)
(tree-map identity change-str tree))
(define (change-str str)
(if (odd? (string-length str)) "odd" str))
(define (tree-map func-key func-val tree)
(cond [(empty? tree) tree]
[else (make-node (func-key (node-key tree))
(func-val (node-val tree))
(tree-map func-key func-val (node-left tree))
(tree-map func-key func-val (node-right tree)))]))

Expects 2 arguments but found only 1

I am doing a practice question where it asks to define a function that is supposed to produce all elements in a list, loi, that can be divided by 3 or a natural number, mult, but not both.
Below is my code:
(define (keep-multiples-of-three-or loi mult)
(cond
[(empty? loi) empty]
[else (cond [(empty? loi) empty]
[(and (not (equal? 3 mult))
(or (equal? (remainder (first loi) 3) 0)
(equal? (remainder (first loi) mult) 0)))
(first loi)]
[else (keep-multiples-of-three-or (rest-loi)
mult)]))]))
for (keep-multiples-of-three-or (cons 9 (cons 3 empty)) 3)
the error message says: cons expects 2 arguments but found only 1.
I don’t know what is wrong here. Can somebody help me?
You have a couple of errors:
There's no need to nest the cond expression
The [(empty? loi) empty] case is repeated two times
It's not (rest-loi), it's (rest loi)
In the second case, you need to cons the result and call the recursion again
The (not (equal? 3 mult)) condition is making your example return an empty list, think about it: you're saying that mult is 3, but then you check it mult is not 3
This should fix the issues:
(define (keep-multiples-of-three-or loi mult)
(cond [(empty? loi) empty]
[(or (equal? (remainder (first loi) 3) 0)
(equal? (remainder (first loi) mult) 0))
(cons (first loi)
(keep-multiples-of-three-or (rest loi) mult))]
[else (keep-multiples-of-three-or (rest loi) mult)]))
For example:
(keep-multiples-of-three-or (list 9 3) 3)
=> '(9 3)
(keep-multiples-of-three-or (list 1 3 5 9) 5)
=> '(3 5 9)

Print values, not types (Racket)

When I print in Racket, only the type is printed of structures, not the value. (I'm working in DrRacket, in the interactions area.)
For example, I have a tree structure:
#lang racket
(define-struct node [name left right])
An example could be:
(define SALLY (make-node 'sally BOBBY SUSIE))
(define BOBBY (make-node 'bobby NONE NONE))
(define SUSIE (make-node 'susie NONE NONE))
What I see:
> (print SALLY)
#<node>
What I want to see:
> (print SALLY)
(make-node 'sally (make-node 'bobby NONE NONE)
(make-node 'susie NONE NONE))
How can I see the value and not the type?
Use #:transparent keyword:
(define-struct node [name left right] #:transparent)
> (define-struct node [name left right] #:transparent)
> (define NONE '())
> (define BOBBY (make-node 'bobby NONE NONE))
> (define SUSIE (make-node 'susie NONE NONE))
> (define SALLY (make-node 'sally BOBBY SUSIE))
> (print SALLY)
(node 'sally (node 'bobby '() '()) (node 'susie '() '()))
NB: Today struct is preferred over define-struct so I've written the code with struct.
It doesn't really print the type but it's the default representation of the object. There are two options you can do:
1. Use #:transparent keyword.
(struct node [name left right] #:transparent)
(define root (node 'd
(node 'b (node 'a '() '())
(node 'c '() '()))
(node 'f (node 'e '() '())
(node 'g '() '()))))
root ; ==>
; (node 'd
; (node 'b (node 'a '() '())
; (node 'c '() '()))
; (node 'f (node 'e '() '())
; (node 'g '() '()))))
Notice how they look like the construction?
1. Add a writer for the object
(struct node [name left right]
#:methods gen:custom-write
[;; needs to be named write-proc
(define (write-proc x port mode)
((if (eq? mode #t) write display) (fancy-writer x 0) port))
;; helper used by write-proc
(define (fancy-writer x ident)
(if (null? x)
""
(let ([new-ident (+ 5 ident)])
(string-append (fancy-writer (node-left x) new-ident)
(string-append (make-string ident #\space)
(symbol->string (node-name x))
"\n")
(fancy-writer (node-right x) new-ident)))))])
root ; ==>
; a
; b
; c
; d
; e
; f
; g

DrRacket mutually recursive functions with accumulator

(define-struct person (name house kids))
;; A Person is (make-person String String ListOfPerson)
;; interp. A person, with name, house and list of children.
(define P0 (make-person "Draco" "Slytherin" empty))
(define P1 (make-person "Nymphadora" "Hufflepuff" empty))
(define P2 (make-person "Sirius" "Griffindor" empty))
(define P3 (make-person "Regulus" "Slytherin" empty))
(define P4 (make-person "Bellatrix" "Slytherin" empty))
(define P5 (make-person "Andromeda" "Slytherin" (list P1)))
(define P6 (make-person "Narcissa" "Slytherin" (list P0)))
(define P7 (make-person "Walburga" "Slytherin" (list P2 P3)))
(define P8 (make-person "Alphard" "Slytherin" empty))
(define P9 (make-person "Cygnus" "Slytherin" (list P4 P5 P6)))
(define P10 (make-person "Irma" "Slytherin" (list P7 P8 P9)))
original structured reference
;; Person -> Natural
;; Count number of people in a tree
(check-expect (count P0) 1)
(check-expect (count P5) 2)
(check-expect (count P10) 11)
(define (count p)
(local
[(define (count/person p)
(add1 (count/lop (person-kids p))))
(define (count/lop lop)
(cond [(empty? lop) 0]
[else
(+ (count/person (first lop))
(count/lop (rest lop)))]))]
(count/person p)))
this is the solution
(define (count p)
(local
[(define (count/person p result todo)
(count/lop (add1 result)
(append (person-kids p) todo)))
(define (count/lop result todo)
(cond [(empty? todo) result]
[else
(count/person (first todo)
result
(rest todo))]))])
(count/person p 0 empty))
;; Accumulator result is Natural
;; Invariant: the total computed so far
;; Accumulator todo is (listof Person)
;; Invariant: persons not yet visited by count/person
I have trouble understand how this comes from the initial normal mutual reference solution, could anyone explain this to me?
Your solution does not follow the basic design recipe.
Here is an attempt to make a straight-forward solution:
(define-struct person (kids))
; sum : list-of-numbers -> number
(define (sum xs)
(cond
[(empty? xs) 0]
[else (+ (first xs) (sum (rest xs)))]))
; count : person -> number
(define (count p)
(cond
[(empty? (person-kids p)) 1] ; p is 1 person, 0 kids
[else (+ 1 ; p is 1 person and
(sum (map count ; we must sum over the
(person-kids p))))])) ; count of each kid
In chapter 30 and 31 of How to Design Programs, you can read about the conversion from this style to accumulator style (which your solution uses). Details in the conversion is in section 31.3.
HtDP section 31.3 'Transforming Functions into Accumulator-Style'