123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442 |
- ; Copyright (c) 1993-2007 by Richard Kelsey and Jonathan Rees. See file COPYING.
- ; Red-Black binary search trees as described in Introduction to Algorithms
- ; by Cormen, Leiserson, and Rivest. Look there if you want to understand
- ; the algorithm.
- ;
- ; These are like tables in that the value of a key defaults to #f.
- ;
- ; (make-search-tree key-= key-<) -> tree
- ;
- ; (search-tree? value) -> boolean
- ;
- ; (search-tree-ref tree key) -> value
- ;
- ; (search-tree-set! tree key value)
- ;
- ; (search-tree-modify! tree key proc)
- ; == (search-tree-set! tree key (proc (search-tree-ref tree key)))
- ;
- ; (search-tree-max tree) -> key + value
- ; (pop-search-tree-max! tree) -> key + value (removes entry)
- ;
- ; (search-tree-min tree) -> key + value
- ; (pop-search-tree-min! tree) -> key + value (removes entry)
- ;
- ; (walk-search-tree proc tree)
- ; applies PROC in order to all key + value pairs with a non-#f value
- (define-record-type tree :tree
- (make-tree lookup nil root)
- search-tree?
- (lookup tree-lookup)
- (nil tree-nil) ; node marker for missing leaf nodes
- (root tree-root set-tree-root!))
- (define (make-search-tree = <)
- (let ((nil (make-node #f #f #f)))
- (set-node-red?! nil #f)
- (make-tree (make-lookup = <) nil #f)))
- (define-record-type node :node
- (really-make-node key value parent red? left right)
- node?
- (key node-key set-node-key!)
- (value node-value set-node-value!)
- (parent node-parent set-node-parent!) ; #f in the root node
- (red? node-red? set-node-red?!) ; for balancing the tree
- (left node-left set-node-left!) ; left and
- (right node-right set-node-right!)) ; right subtrees
- (define (make-node key value parent)
- (really-make-node key value parent #t #f #f))
- (define-record-discloser :node
- (lambda (node)
- (list 'node (node-key node))))
- ; Lookup up KEY and return its value.
- (define (search-tree-ref tree key)
- (call-with-values
- (lambda ()
- ((tree-lookup tree) tree key))
- (lambda (node parent left?)
- (if node
- (node-value node)
- #f))))
- ; Adding and modifying entries.
- (define (search-tree-set! tree key value)
- (search-tree-modify! tree key (lambda (ignore) value)))
- (define (search-tree-modify! tree key proc)
- (call-with-values
- (lambda ()
- ((tree-lookup tree) tree key))
- (lambda (node parent left?)
- (let ((new-value (proc (if node (node-value node) #f))))
- (cond ((and node new-value)
- (set-node-value! node new-value))
- (new-value
- (really-insert! tree parent left? (make-node key new-value parent)))
- (node
- (really-delete! tree node)))))))
-
- ; Min and max entries.
- (define (search-tree-max tree)
- (real-search-tree-max tree #f))
- (define (pop-search-tree-max! tree)
- (real-search-tree-max tree #t))
- (define (real-search-tree-max tree delete?)
- (let ((node (tree-root tree)))
- (if node
- (let loop ((node node))
- (cond ((node-right node)
- => loop)
- (else
- (if delete?
- (really-delete! tree node))
- (values (node-key node) (node-value node)))))
- (values #f #f))))
- (define (search-tree-min tree)
- (real-search-tree-min tree #f))
- (define (pop-search-tree-min! tree)
- (real-search-tree-min tree #t))
- (define (real-search-tree-min tree delete?)
- (let ((node (tree-root tree)))
- (if node
- (let loop ((node node))
- (cond ((node-left node)
- => loop)
- (else
- (if delete?
- (really-delete! tree node))
- (values (node-key node) (node-value node)))))
- (values #f #f))))
- (define (walk-search-tree proc tree)
- (let recur ((node (tree-root tree)))
- (cond (node
- (recur (node-left node))
- (proc (node-key node) (node-value node))
- (recur (node-right node))))))
- ; Lookup up an entry. Easy.
- ;
- ; Hack of checking common case reduced lookup time in a 1000 element search
- ; tree by a third.
- (define (make-lookup tree-= tree-<)
- (if (and (eq? tree-= =)
- (eq? tree-< <))
- default-lookup
- (lambda (tree key)
- (let loop ((node (tree-root tree))
- (parent #f)
- (left? #f))
- (cond ((not node)
- (values #f parent left?))
- ((tree-= (node-key node) key)
- (values node #f #f))
- ((tree-< key (node-key node))
- (loop (node-left node) node #t))
- (else
- (loop (node-right node) node #f)))))))
- (define (default-lookup tree key)
- (let loop ((node (tree-root tree))
- (parent #f)
- (left? #f))
- (cond ((not node)
- (values #f parent left?))
- ((= (node-key node) key)
- (values node #f #f))
- ((< key (node-key node))
- (loop (node-left node) node #t))
- (else
- (loop (node-right node) node #f)))))
- ;----------------------------------------------------------------
- ; Little utilities.
- ; Parameterized node access
- (define (node-child node left?)
- (if left?
- (node-left node)
- (node-right node)))
- (define (set-node-child! node left? child)
- (if left?
- (set-node-left! node child)
- (set-node-right! node child)))
- ; Empty leaf slots are considered black.
- (define (node-black? node)
- (not (and node (node-red? node))))
- ; The next node (used in REALLY-DELETE!)
- (define (successor node)
- (cond ((node-right node)
- => (lambda (node)
- (let loop ((node node))
- (cond ((node-left node)
- => loop)
- (else node)))))
- (else
- (let loop ((node node) (parent (node-parent node)))
- (if (and parent
- (eq? node (node-right parent)))
- (loop parent (node-parent parent))
- parent)))))
- ;----------------------------------------------------------------
- ; Add NODE as the LEFT? child of PARENT and balance the tree.
- (define (really-insert! tree parent left? node)
- (if (not parent)
- (set-tree-root! tree node)
- (set-node-child! parent left? node))
- (fixup-insertion! node tree))
- ; Balance the tree after NODE has been inserted.
- (define (fixup-insertion! node tree)
- (let loop ((node node))
- (let ((parent (node-parent node)))
- (if (and parent (node-red? parent))
- (let* ((grand (node-parent parent))
- (left? (eq? parent (node-left grand)))
- (y (node-child grand (not left?))))
- (cond ((node-black? y)
- (let* ((node (cond ((eq? node (node-child parent (not left?)))
- (rotate! parent left? tree)
- parent)
- (else node)))
- (parent (node-parent node))
- (grand (node-parent parent)))
- (set-node-red?! parent #f)
- (set-node-red?! grand #t)
- (rotate! grand (not left?) tree)
- (loop node)))
- (else
- (set-node-red?! parent #f)
- (set-node-red?! y #f)
- (set-node-red?! grand #t)
- (loop grand)))))))
- (set-node-red?! (tree-root tree) #f))
- ; A B
- ; / \ =(rotate! A #f tree)=> / \
- ; B k i A
- ; / \ <=(rotate! B #t tree)= / \
- ; i j j k
- (define (rotate! node left? tree)
- (let* ((y (node-child node (not left?)))
- (y-left (node-child y left?))
- (parent (node-parent node)))
- (set-node-child! node (not left?) y-left)
- (if y-left
- (set-node-parent! y-left node))
- (replace! parent y node tree)
- (set-node-child! y left? node)
- (set-node-parent! node y)))
-
- ; Replace CHILD (of PARENT) with NEW-CHILD
- (define (replace! parent new-child child tree)
- (set-node-parent! new-child parent)
- (cond ((eq? child (tree-root tree))
- (set-tree-root! tree new-child))
- ((eq? child (node-left parent))
- (set-node-left! parent new-child))
- (else
- (set-node-right! parent new-child))))
- ; Remove NODE from tree.
- (define (really-delete! tree node)
- (let* ((y (cond ((or (not (node-left node))
- (not (node-right node)))
- node)
- (else
- (let ((y (successor node)))
- (set-node-key! node (node-key y))
- (set-node-value! node (node-value y))
- y))))
- (x (or (node-left y)
- (node-right y)
- (let ((x (tree-nil tree)))
- (set-node-right! y x)
- x)))
- (parent (node-parent y)))
- (replace! parent x y tree)
- (if (not (node-red? y))
- (fixup-delete! x tree))
- (let ((nil (tree-nil tree)))
- (cond ((node-parent nil)
- => (lambda (p)
- (if (eq? (node-right p) nil)
- (set-node-right! p #f)
- (set-node-left! p #f))
- (set-node-parent! (tree-nil tree) #f)))
- ((eq? nil (tree-root tree))
- (set-tree-root! tree #f))))))
- (define (fixup-delete! x tree)
- (let loop ((x x))
- (if (or (eq? x (tree-root tree))
- (node-red? x))
- (set-node-red?! x #f)
- (let* ((parent (node-parent x))
- (left? (eq? x (node-left parent)))
- (w (node-child parent (not left?)))
- (w (cond ((node-red? w)
- (set-node-red?! w #f)
- (set-node-red?! parent #t)
- (rotate! parent left? tree)
- (node-child (node-parent x) (not left?)))
- (else
- w))))
- (cond ((and (node-black? (node-left w))
- (node-black? (node-right w)))
- (set-node-red?! w #t)
- (loop (node-parent x)))
- (else
- (let ((w (cond ((node-black? (node-child w (not left?)))
- (set-node-red?! (node-child w left?) #f)
- (set-node-red?! w #t)
- (rotate! w (not left?) tree)
- (node-child (node-parent x) (not left?)))
- (else
- w))))
- (let ((parent (node-parent x)))
- (set-node-red?! w (node-red? parent))
- (set-node-red?! parent #f)
- (set-node-red?! (node-child w (not left?)) #f)
- (rotate! parent left? tree)
- (set-node-red?! (tree-root tree) #f)))))))))
-
- ; Verify that the coloring is correct
- ;
- ;(define (okay-tree? tree)
- ; (receive (okay? red? count)
- ; (let recur ((node (tree-root tree)))
- ; (if (not node)
- ; (values #t #f 0)
- ; (receive (l-ok? l-r? l-c)
- ; (recur (node-left node))
- ; (receive (r-ok? r-r? r-c)
- ; (recur (node-right node))
- ; (values (and l-ok?
- ; r-ok?
- ; (not (and (node-red? node)
- ; (or l-r? r-r?)))
- ; (= l-c r-c))
- ; (node-red? node)
- ; (if (node-red? node)
- ; l-c
- ; (+ l-c 1)))))))
- ; okay?))
- ;
- ;
- ;(define (walk-sequences proc list)
- ; (let recur ((list list) (r '()))
- ; (if (null? list)
- ; (proc (reverse r))
- ; (let loop ((list list) (done '()))
- ; (if (not (null? list))
- ; (let ((next (car list)))
- ; (recur (append (reverse done) (cdr list)) (cons next r))
- ; (loop (cdr list) (cons next done))))))))
- ;
- ;(define (tree-test n)
- ; (let ((iota (do ((i n (- i 1))
- ; (l '() (cons i l)))
- ; ((<= i 0) l))))
- ; (walk-sequences (lambda (in)
- ; (walk-sequences (lambda (out)
- ; (do-tree-test in out))
- ; iota))
- ; iota)
- ; #t))
- ;
- ;(define (do-tree-test in out)
- ; (let ((tree (make-search-tree = <)))
- ; (for-each (lambda (i)
- ; (search-tree-set! tree i (- 0 i)))
- ; in)
- ; (if (not (okay-tree? tree))
- ; (breakpoint "tree ~S is not okay" in))
- ; (if (not (tree-ordered? tree (length in)))
- ; (breakpoint "tree ~S is not ordered" in))
- ; (for-each (lambda (i)
- ; (if (not (= (search-tree-ref tree i) (- 0 i)))
- ; (breakpoint "looking up ~S in ~S lost" i in)))
- ; in)
- ; (do ((o out (cdr o)))
- ; ((null? o))
- ; (search-tree-set! tree (car o) #f)
- ; (if (not (okay-tree? tree))
- ; (breakpoint "tree ~S is not okay after deletions ~S" in out)))))
- ;
- ;(define (tree-ordered? tree count)
- ; (let ((l '()))
- ; (walk-search-tree (lambda (key value)
- ; (set! l (cons (cons key value) l)))
- ; tree)
- ; (let loop ((l l) (n count))
- ; (cond ((null? l)
- ; (= n 0))
- ; ((and (= (caar l) n)
- ; (= (cdar l) (- 0 n)))
- ; (loop (cdr l) (- n 1)))
- ; (else #f)))))
- ;
- ;(define (do-tests tester)
- ; (do ((i 0 (+ i 1)))
- ; (#f)
- ; (tester i)
- ; (format #t " done with ~D~%" i)))
- ;
- ;(define (another-test n)
- ; (let ((iota (do ((i n (- i 1))
- ; (l '() (cons i l)))
- ; ((<= i 0) l))))
- ; (walk-sequences (lambda (in)
- ; (do ((i 1 (+ i 1)))
- ; ((> i n))
- ; (let ((tree (make-search-tree = <)))
- ; (for-each (lambda (i)
- ; (search-tree-set! tree i (- 0 i)))
- ; in)
- ; (if (not (okay-tree? tree))
- ; (breakpoint "tree ~S is not okay" in))
- ; (if (not (tree-ordered? tree (length in)))
- ; (breakpoint "tree ~S is not ordered" in))
- ; (for-each (lambda (i)
- ; (if (not (= (search-tree-ref tree i) (- 0 i)))
- ; (breakpoint "looking up ~S in ~S lost" i in)))
- ; in)
- ; (search-tree-set! tree i #f)
- ; (if (not (okay-tree? tree))
- ; (breakpoint "tree ~S is not okay after deletion ~S"
- ; in i))
- ; (for-each (lambda (j)
- ; (let ((ref (search-tree-ref tree j)))
- ; (if (not (eq? ref (if (= j i) #f (- 0 j))))
- ; (breakpoint "looking up ~S in ~S lost" i in))))
- ; in))))
- ; iota)))
|