scsh-0.5/big/search-tree.scm

398 lines
12 KiB
Scheme

; Copyright (c) 1993, 1994 Richard Kelsey and Jonathan Rees. See file COPYING.
;Date: Thu, 4 Nov 93 13:30:46 EST
;To: jar@ai.mit.edu
;Subject: binary search trees
;From: kelsey@research.nj.nec.com
;
;
;For no particular reason I implemented balanced binary search
;trees as another random data structure to go in big. The only
;things it uses from BIG-SCHEME are DEFINE-RECORD-TYPE and
;RECEIVE.
;
;(define-interface search-tree-interface
; (export make-search-tree
; search-tree-ref
; search-tree-set!
; search-tree-modify!
; search-tree-max
; search-tree-min
; walk-search-tree))
;
;(define-structure search-tree search-tree-signature
; (open big-scheme scheme)
; (files (big search-tree)))
; Red-Black binary search trees as described in Introduction to Algorithms
; by Cormen, Leiserson, and Rivest.
;
; (make-search-tree key-= key-<) -> tree
;
; (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
;
; (search-tree-min tree) -> key + value
;
; (walk-search-tree proc tree)
; applies PROC in order to all key + value pairs with a non-#F value
(define-record-type tree
(lookup
nil) ; node marker for missing leaf nodes (used in REALLY-DELETE!)
((root #f)))
(define (make-search-tree = <)
(let ((nil (make-node #f #f #f)))
(set-node-red?! nil #f)
(tree-maker (make-lookup = <) nil)))
(define-record-type node
((key)
(value)
(parent)) ; #F for the root node
((red? #t)
(left #f)
(right #f)))
(define make-node node-maker)
(define-record-discloser type/node
(lambda (node)
(list 'node (node-key node))))
(define (search-tree-ref tree key)
(receive (node parent left?)
((tree-lookup tree) tree key)
(if node
(node-value node)
#f)))
(define (search-tree-set! tree key value)
(search-tree-modify! tree key (lambda (ignore) value)))
(define (search-tree-modify! tree key proc)
(receive (node parent left?)
((tree-lookup tree) tree key)
(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))))))
(define (search-tree-max tree)
(let ((node (tree-root tree)))
(if node
(let loop ((node node))
(cond ((node-right node)
=> loop)
(else
(values (node-key node) (node-value node)))))
(values #f #f))))
(define (search-tree-min tree)
(let ((node (tree-root tree)))
(if node
(let loop ((node node))
(cond ((node-left node)
=> loop)
(else
(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))))))
(define (make-lookup = <)
(lambda (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))))))
; 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)))))
(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))
(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))))
(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)))