;;; -*- Mode: Scheme -*- ;;;; Binary Trees of Bounded Balance ;;; Copyright (c) 2009, Taylor R. Campbell ;;; ;;; Redistribution and use in source and binary forms, with or without ;;; modification, are permitted provided that the following conditions ;;; are met: ;;; ;;; * Redistributions of source code must retain the above copyright ;;; notice, this list of conditions and the following disclaimer. ;;; ;;; * Redistributions in binary form must reproduce the above copyright ;;; notice, this list of conditions and the following disclaimer in ;;; the documentation and/or other materials provided with the ;;; distribution. ;;; ;;; * Neither the names of the authors nor the names of contributors ;;; may be used to endorse or promote products derived from this ;;; software without specific prior written permission. ;;; ;;; THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS ;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY ;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ;;; This file implements maps by binary trees of bounded balance, ;;; described in ;;; ;;; J. Nievergelt and E.M. Reingold, `Binary search trees of bounded ;;; balance', ACM SIGACT, 1972. ;;; ;;; S. Adams, `Implementing Sets Efficiently in a Functional ;;; Language', Technical Report CSTR 92-10, University of ;;; Southampton. ;;; ;;; This code depends on SRFI 9 (DEFINE-RECORD-TYPE), SRFI 8 (RECEIVE), ;;; and SRFI 23 (ERROR). ;;; ;;; Documentation is forthcoming. ;;; ;;; WARNING: The balance criterion in this code is broken and I ;;; haven't found a round tuit to fix it. See ;;; ;;; Yoichi Hirai and Kazuhiko Yamamoto, `Balancing weight-balanced ;;; trees', Journal of Functional Programming 21(3), pp. 287--307, ;;; 2011. ;;; https://yoichihirai.com/bst.pdf ;;; ;;; for details of what went wrong in Adams' paper (and the parameters ;;; heuristically chosen here). This ought to be replaced by the much ;;; simpler logarithmic balancing criterion in ;;; ;;; Salvador Roura, `A new method for balancing binary search ;;; trees', Automata, Languages, and Programming, Orejas, F., ;;; Spirakis, P., & van Leeuwen, J. (eds), Lecture Notes in Computer ;;; Science 2076, pp. 469--480, Springer, 2001. ;;; (define-record-type (%make-bb-tree-type key-comparator key-order-predicate operation/find-node) bb-tree-type? (key-comparator bb-tree-type.key-comparator) (key-order-predicate bb-tree-type.key-order-predicate) (operation/find-node bb-tree-type.operation/find-node)) (define-record-type (%make-bb-tree type root) bb-tree? (type bb-tree.type) (root bb-tree.root)) (define (make-bb-tree type) (%make-bb-tree type (non-node))) (define (bb-tree/type bb-tree) (bb-tree.type bb-tree)) (define (bb-tree/count bb-tree) (node/count (bb-tree.root bb-tree))) (define (bb-tree/empty? bb-tree) (not (node? (bb-tree.root bb-tree)))) (define (bb-tree-type/key-order-predicate bb-tree-type) (bb-tree-type.key-order-predicate bb-tree-type)) (define (bb-tree-type/key-comparator bb-tree-type) (bb-tree-type.key-comparator bb-tree-type)) (define (error:not-comparison object) (error "Not a comparison:" object)) (define (error:not-alist object) (error "Not an alist:" object)) (define (bb-trees/type bb-tree-a bb-tree-b) (let ((type (bb-tree.type bb-tree-a))) (if (not (eq? type (bb-tree.type bb-tree-b))) (error "BB-trees with mismatched types:" bb-tree-a bb-tree-b)) type)) (define (bb-tree/find-node bb-tree key) ((bb-tree-type.operation/find-node (bb-tree.type bb-tree)) (bb-tree.root bb-tree) key)) (define (bb-tree/search bb-tree key if-found if-not-found) (let ((node (bb-tree/find-node bb-tree key))) (if (node? node) (if-found (node.datum node)) (if-not-found)))) (define (bb-tree/lookup bb-tree key default) (let ((node (bb-tree/find-node bb-tree key))) (if (node? node) (node.datum node) default))) (define (bb-tree/member? bb-tree key) (node? (bb-tree/find-node bb-tree key))) ;;; We can choose a more efficient search algorithm to minimize the ;;; average number of comparisons depending on whether we have an order ;;; predicate or a comparator, provided that it not be defined in terms ;;; of the other construct. If you have both handy, just use the ;;; comparator: it's better overall, and it's what most of the rest of ;;; the bb-tree implementation uses. (define (make-bb-tree-type/order-predicate key (%make-node count left key datum right) node? (count node.count) (left node.left) (key node.key) (datum node.datum) (right node.right)) (define (non-node) #f) (define (node-components* n) (values (node.count n) (node.left n) (node.key n) (node.datum n) (node.right n))) (define (node-components n) (values (node.left n) (node.key n) (node.datum n) (node.right n))) (define (make-leaf key datum) (%make-node 1 (non-node) key datum (non-node))) ;;; Assumption: LEFT and RIGHT are balanced internally, and the two are ;;; balanced with respect to one another. ;;; ;;; Sometimes we use %MAKE-NODE, rather than MAKE-NODE, when we have ;;; already fetched the sizes of the left and right branches, because ;;; that measurably improves performance. (define (make-node left key datum right) (%make-node (+ (node/count left) 1 (node/count right)) left key datum right)) (define (node/count node) (if (node? node) (node.count node) 0)) (define (bb-tree/check tree fail) (let recur ((node (bb-tree.root tree))) (if (node? node) (receive (c l k d r) (node-components* node) k d ;ignore (let ((left-count (recur l)) (right-count (recur r))) (if (not (or (<= (+ left-count right-count) 1) (and (<= left-count (* (balance:w) right-count)) (<= right-count (* (balance:w) left-count))))) (fail "BB-Tree Check -- Balance violation:" node)) (if (not (= c (+ left-count 1 right-count))) (fail "BB-Tree Check -- Count violation:" node c left-count right-count)) c)) (begin (if (not (eq? node (non-node))) (fail "BB-Tree Check -- Neither node nor non-node:" node)) 0)))) ;;; Adams' paper claims that if alpha is 1/2, then w must exceed about ;;; 4.646. However, empirically, a random sequence of insertions ;;; followed by a sequence of minimum deletions reliably yields an ;;; unbalanced tree for me when w is 5. Setting w to 4 does not. (define (balance:w) 4) (define (balance:1/alpha) 2) ;;; Assumption: LEFT and RIGHT are each balanced internally, and the ;;; two are unbalanced by at most one node with respect to one another. (define (join-balanced left key datum right) (let ((lc (node/count left)) (rc (node/count right))) (cond ((<= (+ lc rc) 1) (%make-node (+ lc 1 rc) left key datum right)) ((<= (* (balance:w) lc) rc) (rotate-left left lc key datum right)) ((<= (* (balance:w) rc) lc) (rotate-right left key datum right rc)) (else (%make-node (+ lc 1 rc) left key datum right))))) (define (rotate-left left lc key datum right) (receive (rl rk rd rr) (node-components right) (let ((rlc (node/count rl)) (rrc (node/count rr))) (if (< rlc (* (balance:1/alpha) rrc)) (%make-node (+ lc 1 rlc 1 rrc) (%make-node (+ lc 1 rlc) left key datum rl) rk rd rr) (receive (rll rlk rld rlr) (node-components rl) (let ((rllc (node/count rll)) (rlrc (node/count rlr))) (let ((left-count (+ lc 1 rllc)) (right-count (+ rlrc 1 rrc))) (%make-node (+ left-count 1 right-count) (%make-node left-count left key datum rll) rlk rld (%make-node right-count rlr rk rd rr))))))))) (define (rotate-right left key datum right rc) (receive (ll lk ld lr) (node-components left) (let ((llc (node/count ll)) (lrc (node/count lr))) (if (< lrc (* (balance:1/alpha) llc)) (%make-node (+ llc 1 lrc 1 rc) ll lk ld (%make-node (+ lrc 1 rc) lr key datum right)) (receive (lrl lrk lrd lrr) (node-components lr) (let ((lrlc (node/count lrl)) (lrrc (node/count lrr))) (let ((left-count (+ llc 1 lrlc)) (right-count (+ lrrc 1 rc))) (%make-node (+ left-count 1 right-count) (%make-node left-count ll lk ld lrl) lrk lrd (%make-node right-count lrr key datum right))))))))) ;;; Assumption: LEFT and RIGHT are each balanced internally. (define (join left key datum right) (cond ((not (node? left)) (insert-minimum key datum right)) ((not (node? right)) (insert-maximum left key datum)) (else (receive (lc ll lk ld lr) (node-components* left) (receive (rc rl rk rd rr) (node-components* right) (cond ((<= (* (balance:w) lc) rc) (join-balanced (join left key datum rl) rk rd rr)) ((<= (* (balance:w) rc) lc) (join-balanced ll lk ld (join lr key datum right))) (else (%make-node (+ lc 1 rc) left key datum right)))))))) (define (insert-minimum key datum node) (let recur ((node node)) (if (node? node) (receive (nl nk nd nr) (node-components node) (join-balanced (recur nl) nk nd nr)) (make-leaf key datum)))) (define (insert-maximum node key datum) (let recur ((node node)) (if (node? node) (receive (nl nk nd nr) (node-components node) (join-balanced nl nk nd (recur nr))) (make-leaf key datum)))) ;;; Assumption: LEFT and RIGHT are each balanced. (define (concatenate left right) (cond ((not (node? left)) right) ((not (node? right)) left) (else (receive (lc ll lk ld lr) (node-components* left) (receive (rc rl rk rd rr) (node-components* right) (cond ((<= (* (balance:w) lc) rc) (join-balanced (concatenate left rl) rk rd rr)) ((<= (* (balance:w) rc) lc) (join-balanced ll lk ld (concatenate lr right))) (else (concatenate-balanced left right)))))))) ;;; Assumption: LEFT and RIGHT are each balanced internally, and the ;;; two are unbalanced by at most one node with respect to one another. (define (concatenate-balanced left right) (cond ((not (node? left)) right) ((not (node? right)) left) (else (if (< (node.count left) (node.count right)) (receive (key datum right*) (delete-minimum right) (join-balanced left key datum right*)) (receive (left* key datum) (delete-maximum left) (join-balanced left* key datum right)))))) (define (delete-minimum node) (receive (left key datum right) (node-components node) (if (node? left) (receive (key* datum* left*) (delete-minimum left) (values key* datum* (join-balanced left* key datum right))) (values key datum right)))) (define (delete-maximum node) (receive (left key datum right) (node-components node) (if (node? right) (receive (right* key* datum*) (delete-maximum right) (values (join-balanced left key datum right*) key* datum*)) (values left key datum)))) (define (bb-tree/update bb-tree key if-found if-not-found) (let* ((type (bb-tree.type bb-tree)) (compare-keys (bb-tree-type.key-comparator type))) (let loop ((node (bb-tree.root bb-tree)) (replace (lambda (node) (%make-bb-tree type node))) (rebalance (lambda (node) (%make-bb-tree type node)))) (if (node? node) (receive (l k d r) (node-components node) (let ((comparison (compare-keys key k))) (case comparison ((-1) (loop l (lambda (l) (replace (make-node l k d r))) (lambda (l) (rebalance (join-balanced l k d r))))) ((+1) (loop r (lambda (r) (replace (make-node l k d r))) (lambda (r) (rebalance (join-balanced l k d r))))) ((0) (if-found d (lambda (datum) (replace (make-node l key datum r))) (lambda () (rebalance (concatenate-balanced l r))))) (else (error:not-comparison comparison))))) (if-not-found (lambda (datum) (rebalance (make-leaf key datum)))))))) ;; (define (bb-tree/insert bb-tree key datum) ;; (bb-tree/update bb-tree key ;; (lambda (datum* replace delete) ;; datum* delete ;ignore ;; (replace datum)) ;; (lambda (insert) ;; (insert datum)))) (define (bb-tree/modify bb-tree key default modifier) (bb-tree/update bb-tree key (lambda (datum replace delete) delete ;ignore (replace (modifier datum))) (lambda (insert) (insert (modifier default))))) (define (bb-tree/intern bb-tree key generator) (bb-tree/update bb-tree key (lambda (datum replace delete) replace delete ;ignore (values datum bb-tree)) (lambda (insert) (let ((datum (generator key))) (values datum (insert datum)))))) ;; (define (bb-tree/delete bb-tree key) ;; (bb-tree/update bb-tree key ;; (lambda (datum replace delete) ;; datum replace ;ignore ;; (delete)) ;; (lambda (insert) ;; insert ;ignore ;; bb-tree))) ;;; Special cases for insertion and deletion yield small but measurable ;;; performance improvements, even though they cause some superfluous ;;; balancing checks to be done in the case of insertion of an existing ;;; key or the case of deletion of a non-existing key. I have not ;;; compared speed of special cases for modification and internment. (define (bb-tree/insert bb-tree key datum) (let* ((type (bb-tree.type bb-tree)) (compare-keys (bb-tree-type.key-comparator type))) (%make-bb-tree type (let recur ((node (bb-tree.root bb-tree))) (if (node? node) (receive (c l k d r) (node-components* node) (let ((comparison (compare-keys key k))) (case comparison ((-1) (join-balanced (recur l) k d r)) ((+1) (join-balanced l k d (recur r))) ((0) (%make-node c l k datum r)) (else (error:not-comparison comparison))))) (make-leaf key datum)))))) (define (bb-tree/delete bb-tree key) (let* ((type (bb-tree.type bb-tree)) (compare-keys (bb-tree-type.key-comparator type))) (%make-bb-tree type (let recur ((node (bb-tree.root bb-tree))) (if (node? node) (receive (l k d r) (node-components node) (let ((comparison (compare-keys key k))) (case comparison ((-1) (join-balanced (recur l) k d r)) ((+1) (join-balanced l k d (recur r))) ((0) (concatenate-balanced l r)) (else (error:not-comparison comparison))))) (non-node)))))) ;;;; Minimum and Maximum (define (bb-tree/min bb-tree default) (bb-tree/*min bb-tree key*datum->key default)) (define (bb-tree/min-datum bb-tree default) (bb-tree/*min bb-tree key*datum->datum default)) (define (bb-tree/min-pair bb-tree) (bb-tree/*min bb-tree key*datum->pair #f)) (define (bb-tree/max bb-tree default) (bb-tree/*max bb-tree key*datum->key default)) (define (bb-tree/max-datum bb-tree default) (bb-tree/*max bb-tree key*datum->datum default)) (define (bb-tree/max-pair bb-tree) (bb-tree/*max bb-tree key*datum->pair #f)) (define (key*datum->key key datum) datum key) (define (key*datum->datum key datum) key datum) (define (key*datum->pair key datum) (cons key datum)) (define (key*datum->values key datum) (values key datum)) (define (bb-tree/*min bb-tree selector default) (let ((root (bb-tree.root bb-tree))) (if (node? root) (let loop ((node root)) (let ((left (node.left node))) (if (node? left) (loop left) (selector (node.key node) (node.datum node))))) default))) (define (bb-tree/*max bb-tree selector default) (let ((root (bb-tree.root bb-tree))) (if (node? root) (let loop ((node root)) (let ((right (node.right node))) (if (node? right) (loop right) (selector (node.key node) (node.datum node))))) default))) ;;;;; Deleting the Minimum and Maximum (define (bb-tree/delete-min bb-tree default) (bb-tree/*delete-min bb-tree key*datum->key default)) (define (bb-tree/delete-min-datum bb-tree default) (bb-tree/*delete-min bb-tree key*datum->datum default)) (define (bb-tree/delete-min-pair bb-tree) (bb-tree/*delete-min bb-tree key*datum->pair #f)) (define (bb-tree/delete-max bb-tree default) (bb-tree/*delete-max bb-tree key*datum->key default)) (define (bb-tree/delete-max-datum bb-tree default) (bb-tree/*delete-max bb-tree key*datum->datum default)) (define (bb-tree/delete-max-pair bb-tree) (bb-tree/*delete-max bb-tree key*datum->pair #f)) (define (bb-tree/*delete-min bb-tree selector default) (let ((root (bb-tree.root bb-tree))) (if (node? root) (let ((type (bb-tree.type bb-tree))) (receive (key datum root) (delete-minimum (bb-tree.root bb-tree)) (values (selector key datum) (%make-bb-tree type root)))) (values default bb-tree)))) (define (bb-tree/*delete-max bb-tree selector default) (let ((root (bb-tree.root bb-tree))) (if (node? root) (let ((type (bb-tree.type bb-tree))) (receive (root key datum) (delete-maximum (bb-tree.root bb-tree)) (values (selector key datum) (%make-bb-tree type root)))) (values default bb-tree)))) ;;;;; Updating the Minimum and Maximum (define (bb-tree/update-min bb-tree if-found if-empty) (let ((root (bb-tree.root bb-tree))) (if (node? root) (let* ((type (bb-tree.type bb-tree)) (replace-root (lambda (node) (%make-bb-tree type node)))) (let loop ((node root) (replace replace-root) (rebalance replace-root)) (receive (l k d r) (node-components node) (if (node? l) (loop l (lambda (l) (replace (make-node l k d r))) (lambda (l) (rebalance (join-balanced l k d r)))) (if-found k d (lambda (d) (replace (make-node l k d r))) (lambda () (rebalance r))))))) (if-empty)))) (define (bb-tree/update-max bb-tree if-found if-empty) (let ((root (bb-tree.root bb-tree))) (if (node? root) (let* ((type (bb-tree.type bb-tree)) (replace-root (lambda (node) (%make-bb-tree type node)))) (let loop ((node root) (replace replace-root) (rebalance replace-root)) (receive (l k d r) (node-components node) (if (node? r) (loop r (lambda (r) (replace (make-node l k d r))) (lambda (r) (rebalance (join-balanced l k d r)))) (if-found k d (lambda (d) (replace (make-node l k d r))) (lambda () (rebalance l))))))) (if-empty)))) ;;;; Indexing (define (bb-tree/rank bb-tree key) (bb-tree/key->index bb-tree key)) (define (bb-tree/key->index bb-tree key) (let ((compare-keys (bb-tree-type.key-comparator (bb-tree.type bb-tree)))) (let loop ((node (bb-tree.root bb-tree)) (offset 0)) (if (node? node) (receive (l k d r) (node-components node) d ;ignore (let ((comparison (compare-keys key k))) (case comparison ((-1) (loop l offset)) ((+1) (loop r (+ offset (node/count l) 1))) ((0) (+ offset (node/count l))) (else (error:not-comparison comparison))))) #f)))) (define (bb-tree/index bb-tree index) (bb-tree/*index bb-tree index key*datum->key)) (define (bb-tree/index-datum bb-tree index) (bb-tree/*index bb-tree index key*datum->datum)) (define (bb-tree/index-pair bb-tree index) (bb-tree/*index bb-tree index key*datum->pair)) (define (bb-tree/index-key&datum bb-tree index) (bb-tree/*index bb-tree index key*datum->values)) (define (bb-tree/*index bb-tree index selector) (let ((root (bb-tree.root bb-tree))) (let ((count (node/count root))) (if (or (< index 0) (<= count index)) (error "Index out of bounds:" index bb-tree))) ;; The above test, and the loop structure below together with the ;; tree structure, all guarantee that NODE is a non-empty node at ;; entry to the loop. (let loop ((node root) (index index)) (receive (left key datum right) (node-components node) (let ((left-count (node/count left))) (cond ((< index left-count) (loop left index)) ((< left-count index) (loop right (- index (+ left-count 1)))) (else (selector key datum)))))))) ;;;;; Deleting and Replacing at Indices (define (bb-tree/delete-index bb-tree index) (bb-tree/*delete-index bb-tree index key*datum->key)) (define (bb-tree/delete-index-datum bb-tree index) (bb-tree/*delete-index bb-tree index key*datum->datum)) (define (bb-tree/delete-index-pair bb-tree index) (bb-tree/*delete-index bb-tree index key*datum->pair)) (define (bb-tree/delete-index-key&datum bb-tree index) (receive (pair bb-tree) (bb-tree/delete-index-pair bb-tree index) (values (car pair) (cdr pair) bb-tree))) (define (bb-tree/*delete-index bb-tree index selector) (let ((type (bb-tree.type bb-tree)) (root (bb-tree.root bb-tree))) (let ((count (node/count root))) (if (or (< index 0) (<= count index)) (error "Index out of bounds:" index bb-tree))) (call-with-values (lambda () (let recur ((node root) (index index)) (receive (left key datum right) (node-components node) (let ((left-count (node/count left))) (cond ((< index left-count) (receive (result left) (recur left index) (values result (join-balanced left key datum right)))) ((< left-count index) (receive (result right) (recur right (- index (+ left-count 1))) (values result (join-balanced left key datum right)))) (else (values (selector key datum) (concatenate-balanced left right)))))))) (lambda (result root) (values result (%make-bb-tree type root)))))) ;;; Why no INSERT-INDEX? This is a data structure for a set of ;;; associations that happen to be ordered, not a data structure for a ;;; sequence. If you have an association, just insert it the usual ;;; way; it will go in the right place. (define (bb-tree/replace-index bb-tree index datum) (let ((type (bb-tree.type bb-tree)) (root (bb-tree.root bb-tree))) (let ((count (node/count root))) (if (or (< index 0) (<= count index)) (error "Index out of bounds:" index bb-tree))) (%make-bb-tree type (let recur ((node root) (index index)) (receive (count left key datum* right) (node-components* node) (let ((left-count (node/count left))) (cond ((< index left-count) (%make-node count (recur left index) key datum* right)) ((< left-count index) (let ((index (- index (+ left-count 1)))) (%make-node count left key datum* (recur right index)))) (else (%make-node count left key datum right))))))))) ;;;;; Editing at Indices (define (bb-tree/modify-index bb-tree index modifier) (let ((type (bb-tree.type bb-tree)) (root (bb-tree.root bb-tree))) (let ((count (node/count root))) (if (or (< index 0) (<= count index)) (error "Index out of bounds:" index bb-tree))) (%make-bb-tree type (let recur ((node root) (index index)) (receive (count left key datum right) (node-components* node) (let ((left-count (node/count left))) (cond ((< index left-count) (%make-node count (recur left index) key datum right)) ((< left-count index) (let ((index (- index (+ left-count 1)))) (%make-node count left key datum (recur right index)))) (else (let ((datum (modifier key datum))) (%make-node count left key datum right)))))))))) (define (bb-tree/update-index bb-tree index receiver) (let ((type (bb-tree.type bb-tree)) (root (bb-tree.root bb-tree))) (let ((count (node/count root))) (if (or (< index 0) (<= count index)) (error "Index out of bounds:" index bb-tree))) (let ((replace (lambda (root) (%make-bb-tree type root)))) (let loop ((node root) (index index) (replace replace) (rebalance replace)) (receive (left key datum right) (node-components node) (let ((left-count (node/count left))) (cond ((< index left-count) (loop left index (lambda (left) (replace (make-node left key datum right))) (lambda (left) (rebalance (join-balanced left key datum right))))) ((< left-count index) (loop right (- index (+ left-count 1)) (lambda (right) (replace (make-node left key datum right))) (lambda (right) (rebalance (join-balanced left key datum right))))) (else (receiver key datum (lambda (datum) (replace (make-node left key datum right))) (lambda () (rebalance (concatenate-balanced left right)))))))))))) ;;;; Splitting on Pivots ;; (define (bb-tree/split bb-tree key) ;; (values (bb-tree/split< bb-tree key) ;; (bb-tree/split> bb-tree key))) (define (bb-tree/split bb-tree key) (let* ((type (bb-tree.type bb-tree)) (compare-keys (bb-tree-type.key-comparator type))) (call-with-values (lambda () (let recur ((node (bb-tree.root bb-tree))) (if (node? node) (receive (l k d r) (node-components node) (let ((comparison (compare-keys key k))) (case comparison ((-1) (receive (lesser greater) (recur l) (values lesser (join greater k d r)))) ((+1) (receive (lesser greater) (recur r) (values (join l k d lesser) greater))) ((0) (values l r)) (else (error:not-comparison comparison))))) (values (non-node) (non-node))))) (lambda (lesser greater) (values (%make-bb-tree type lesser) (%make-bb-tree type greater)))))) ;; (define (bb-tree/split* bb-tree key if-found if-not-found) ;; (let ((lesser (bb-tree/split< bb-tree key)) ;; (greater (bb-tree/split> bb-tree key))) ;; (bb-tree/search bb-tree key ;; (lambda (datum) (if-found datum lesser greater)) ;; (lambda () (if-not-found lesser greater))))) (define (bb-tree/split* bb-tree key if-found if-not-found) (let* ((type (bb-tree.type bb-tree)) (compare-keys (bb-tree-type.key-comparator type))) (receive (lesser node greater) (split* (bb-tree.root bb-tree) key compare-keys) (let ((lesser (%make-bb-tree type lesser)) (greater (%make-bb-tree type greater))) (if (node? node) (if-found (node.datum node) lesser greater) (if-not-found lesser greater)))))) ;++ This has a mild space leak. It should use a different protocol for ;++ returning the node's datum (and possibly its key), rather than just ;++ returning the node (which hangs on to its (possibly large and now ;++ otherwise unreferenced) children). (define (split* node key compare-keys) (let recur ((node node)) (if (node? node) (receive (l k d r) (node-components node) (let ((comparison (compare-keys key k))) (case comparison ((-1) (receive (lesser node greater) (recur l) (values lesser node (join greater k d r)))) ((+1) (receive (lesser node greater) (recur r) (values (join l k d lesser) node greater))) ((0) (values l node r)) (else (error:not-comparison comparison))))) (values (non-node) (non-node) (non-node))))) (define (bb-tree/split< bb-tree key) (let ((type (bb-tree.type bb-tree))) (%make-bb-tree type (split< (bb-tree.root bb-tree) key (bb-tree-type.key-comparator type))))) (define (bb-tree/split> bb-tree key) (let ((type (bb-tree.type bb-tree))) (%make-bb-tree type (split> (bb-tree.root bb-tree) key (bb-tree-type.key-comparator type))))) (define (split< node key compare-keys) (let recur ((node node)) (if (node? node) (receive (l k d r) (node-components node) (let ((comparison (compare-keys key k))) (case comparison ((-1) (recur l)) ((+1) (join l k d (recur r))) ((0) l) (else (error:not-comparison comparison))))) (non-node)))) (define (split> node key compare-keys) (let recur ((node node)) (if (node? node) (receive (l k d r) (node-components node) (let ((comparison (compare-keys key k))) (case comparison ((-1) (join (recur l) k d r)) ((+1) (recur r)) ((0) r) (else (error:not-comparison comparison))))) (non-node)))) ;;;; Set Operations ;;; TRIM-BETWEEN and TRIM-BETWEEN/MERGE are the basic operations; the ;;; others are specializations omitting lower or upper bounds. The ;;; choice of TRIM-ABOVE/MERGE versus TRIM-BELOW/MERGE is arbitrary. (define (trim-between low high node key bl low compare-keys) bk bd (split< br high compare-keys)))) node-a)) (define (union-above low node-a node-b) (if (node? node-b) (receive (bl bk bd br) (node-components node-b) (if (node? node-a) (receive (al ak ad ar) (node-components node-a) (receive (ad greater) (trim-above/merge ak ad node-b merger compare-keys key bl low compare-keys) bk bd br))) node-a)) (define (union-below high node-a node-b) (if (node? node-b) (receive (bl bk bd br) (node-components node-b) (if (node? node-a) (receive (al ak ad ar) (node-components node-a) (receive (ad greater) (trim-between/merge ak ad high node-b merger compare-keys key al low compare-keys) ak ad (split< ar high compare-keys)))) node-a)) (define (difference-above low node-a node-b) (if (node? node-a) (if (node? node-b) (receive (bl bk bd br) (node-components node-b) bd ;ignore (concatenate (difference-between low bk (trim-between low bk node-a key al low compare-keys) ak ad ar))) node-a)) (define (difference-below high node-a node-b) (if (node? node-a) (if (node? node-b) (receive (bl bk bd br) (node-components node-b) bd ;ignore (concatenate (difference-below bk (trim-below bk node-a key al low compare-keys) ak ad (split< ar high compare-keys)))) node-a)) (define (difference-above low node-a node-b) (if (node? node-a) (if (node? node-b) (receive (bl bk bd br) (node-components node-b) (let ((lesser (trim-between low bk node-a key al low compare-keys) ak ad ar))) node-a)) ;;;;;; Difference with Merging, continued (define (difference-below high node-a node-b) (if (node? node-a) (if (node? node-b) (receive (bl bk bd br) (node-components node-b) (let ((lesser (trim-below bk node-a keylist bb-tree selector) (bb-tree/fold-descending bb-tree '() (lambda (key datum alist) (cons (selector key datum) alist)))) (define (bb-tree->alist bb-tree) (bb-tree->list bb-tree cons)) (define (bb-tree/key-list bb-tree) (bb-tree->list bb-tree (lambda (key datum) datum key))) (define (bb-tree/datum-list bb-tree) (bb-tree->list bb-tree (lambda (key datum) key datum))) (define (alist->bb-tree alist type) (let loop ((alist alist) (bb-tree (make-bb-tree type))) (if (pair? alist) (loop (cdr alist) (bb-tree/insert bb-tree (caar alist) (cdar alist))) (begin (if (not (null? alist)) (error:not-alist alist)) bb-tree)))) ;; ;;;; BB-Tree <-> Stream ;; ;; (define (bb-tree->stream bb-tree) ;; (let recur ((node (bb-tree.root bb-tree)) (tail stream-nil)) ;; (lazy (if (node? node) ;; (receive (l k d r) (node-components node) ;; (recur l (stream-cons (cons k d) (recur r tail)))) ;; tail)))) ;; ;; (define (stream->bb-tree stream bb-tree-type) ;; (let loop ((stream stream) (bb-tree (make-bb-tree bb-tree-type))) ;; (if (stream-pair? stream) ;; (loop (stream-cdr stream) ;; (let ((association (stream-car stream))) ;; (bb-tree/insert bb-tree ;; (car association) ;; (cdr association)))) ;; bb-tree))) ;; ;; (define (bb-tree/equal? bb-tree-a bb-tree-b datum=?) ;; (let ((compare-keys ;; (bb-tree-type.key-comparator (bb-trees/type bb-tree-a bb-tree-b)))) ;; (let loop ((stream-a (bb-tree->stream bb-tree-a)) ;; (stream-b (bb-tree->stream bb-tree-b))) ;; (if (stream-pair? stream-a) ;; (and (stream-pair? stream-b) ;; (let ((association-a (stream-car stream-a)) ;; (association-b (stream-car stream-b))) ;; (let ((comparison ;; (compare-keys (car asosciation-a) ;; (car association-b)))) ;; (case comparison ;; ((0) ;; (and (datum=? (cdr association-a) (cdr association-b)) ;; (loop (stream-cdr stream-a) ;; (stream-cdr stream-b)))) ;; ((-1 +1) #f) ;; (else (error:not-comparison comparison)))))) ;; (not (stream-pair? stream-b)))))) ;; ;; (define (bb-tree/set-equal? bb-tree-a bb-tree-b) ;; (bb-tree/equal? bb-tree-a bb-tree-b (lambda (a b) a b #t))) ;; ;; ;;; Iterator for foof-loop; see ;; ;;; . ;; ;; (define-syntax in-bb-tree ;; (syntax-rules () ;; ((IN-BB-TREE (key-variable datum-variable) ;; (bb-tree-expression) ;; next . rest) ;; (next (((BB-TREE) bb-tree-expression)) ;Outer bindings ;; ((STREAM (BB-TREE->STREAM BB-TREE) ;Loop variables ;; STREAM*)) ;; () ;Entry bindings ;; ((NOT (STREAM-PAIR? STREAM))) ;Termination conditions ;; (((key-variable datum-variable) ;Body bindings ;; (LET ((ASSOCIATION (STREAM-CAR STREAM))) ;; (VALUES (CAR ASSOCIATION) (CDR ASSOCIATION)))) ;; ((STREAM*) (STREAM-CDR STREAM))) ;; () ;Final bindings ;; next . rest)))) ;;;; Miscellaneous BB-Tree Types ;;; Why order predicates rather than comparators here? Scheme comes ;;; with built-in order predicates but no built-in comparators. (define (symbolstring a) (symbol->string b))) (define bb-tree-type:real-number (make-bb-tree-type/order-predicate <)) (define bb-tree-type:exact-integer (make-bb-tree-type/order-predicate <)) (define bb-tree-type:symbol (make-bb-tree-type/order-predicate symbol