(declare (unit util-bst)) (import duck) (module* util-bst #:doc ("Binary Search Tree implementation") ( make-bst bst? bst-EQ? bst-count bst-empty? bst-ref bst-contains? bst-set bst-remove bst-keys bst->kvv kvv->bst kvv-filter bst-balance bst-find-pair bst-filter-pairs bst-map-list bst-map-bst list->bst bst-update bst-filter bst-reduce bst-equal? util-bst-tests! ) (import scheme (chicken condition) (chicken sort) util-tag testing racket-kwargs) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Node ;; Creates BST node with no children (define (make-bst-node key value) (cons (cons key value) (cons #f #f))) ;; Read-only accessors to BST node (define bst-node-kv car) (define bst-node-key caar) (define bst-node-value cdar) (define bst-node-left cadr) (define bst-node-right cddr) ;; Returns BST node with updated node value (define (set-bst-node-value n v) (cons (cons (bst-node-key n) v) (cdr n))) ;; Updates BST node left child (define (set-bst-node-left n l) (cons (car n) (cons l (bst-node-right n)))) ;; Updates BST node right child (define (set-bst-node-right n r) (cons (car n) (cons (bst-node-left n) r))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; BST ;; Unique tag (define TAG-BST (make-tag bst)) (define/doc (make-bst subtag EQ? kvv bst) (let ((vec (make-vector (bst-count bst))) (idx 0)) (bst-iter-kv bst (lambda (kv) (vector-set! vec idx kv) (set! idx (add1 idx)))) (cons TAG-KVV (cons vec (cddr bst))))) ;; Converts a vector of key-value cons cells to BST dictionary (define (kvv->bst kvv) (let* ((vec (cadr kvv)) (count (vector-length vec))) (cons TAG-BST (cons (cons (let loop ((s 0) (e count)) (if (= s e) #f (let* ((c (- e s)) (h (quotient c 2)) (m (+ s h)) (kv (vector-ref vec m))) (cons kv (cons (loop s m) (loop (add1 m) e)))))) count) (cddr kvv))))) ;; Returns KVV that contains only KV pairs matching pred? (define (kvv-filter kvv pred?) (cons (car kvv) (cons (apply vector (let ((vec (cadr kvv))) (let loop ((idx (sub1 (vector-length vec))) (res '())) (if (< idx 0) res (let ((kv (vector-ref vec idx))) (loop (if (pred? (car kv) (cdr kv)) (cons kv res) res) (sub1 idx))))))) (cddr kvv)))) (define/doc (bst-balance bst) ("Unconditionally balances the BST.") (kvv->bst (bst->kvv bst))) (define/doc (bst-find-pair bst pred?) ("Finds pair by predicate that accepts both key and value.") (call/cc (lambda (cc) (bst-iter-kv bst (lambda (kv) (when (pred? (car kv) (cdr kv)) (cc kv)))) #f))) (define/doc (bst-filter-pairs bst pred?) ("Returns a list of key-value pairs matching predicate.") (let ((res '())) (bst-iter-kv bst (lambda (kv) (when (pred? (car kv) (cdr kv)) (set! res (cons kv res))))) (reverse res))) (define/doc (bst-map-list bst proc) ("Returns arbitrary list created by mapping all elements.") (let ((res '())) (bst-iter-kv bst (lambda (kv) (set! res (cons res (proc (car kv) (cdr kv)))))) (reverse res))) (define/doc (bst-map-bst bst proc) ("Returns a new dictionary with all values processed (keys are left intact).") (set-bst-root bst (let loop ((n (bst-root bst))) (if n (cons (cons (caar n) (proc (caar n) (cdar n))) (cons (loop (cadr n)) (loop (cddr n)))) #f)))) (define/doc (list->bst lst subtag EQ? bst (cons TAG-KVV (cons (list->vector (sort lst (lambda (akv bkv) (bst (cons TAG-KVV (cons (apply vector (bst-filter-pairs bst pred?)) (cddr bst))))) (define/doc (bst-reduce bst proc init) ("Like generic reduce, the proc gets accumulator, key and value arguments.") (let ((acc init)) (bst-iter-kv bst (lambda (kv) (set! acc (proc acc (car kv) (cdr kv))))) acc)) ;; Returns true if these are compatible BSTs (define (bst-compat? b1 b2) (and (eq? (bst-tag b1) (bst-tag b2)) (eq? (bst-subtag b1) (bst-subtag b2)) (eq? (bst-EQ? b1) (bst-EQ? b2)) (eq? (bst-