factor/extra/trees/trees.factor

193 lines
5.4 KiB
Factor

! Copyright (C) 2007 Alex Chapman
! See http://factorcode.org/license.txt for BSD license.
USING: kernel generic math math.parser sequences arrays io namespaces
namespaces.private random layouts ;
IN: trees
TUPLE: tree root ;
: <tree> ( -- tree ) tree construct-empty ;
TUPLE: node key value left right ;
: <node> ( value key -- node )
swap f f node construct-boa ;
SYMBOL: current-side
: left -1 ; inline
: right 1 ; inline
: go-left? ( -- ? ) current-side get left = ;
: node-link@ ( -- ? quot quot ) go-left? [ node-left ] [ node-right ] ; inline
: set-node-link@ ( -- ? quot quot ) go-left? [ set-node-left ] [ set-node-right ] ; inline
: node-link ( node -- child ) node-link@ if ;
: set-node-link ( child node -- ) set-node-link@ if ;
: node+link ( node -- child ) node-link@ swap if ;
: set-node+link ( child node -- ) set-node-link@ swap if ;
: with-side ( side quot -- ) H{ } clone >n swap current-side set call ndrop ; inline
: with-other-side ( quot -- ) current-side get neg swap with-side ; inline
: go-left ( quot -- ) left swap with-side ; inline
: go-right ( quot -- ) right swap with-side ; inline
GENERIC: create-node ( value key tree -- node )
GENERIC: copy-node-contents ( new old -- )
M: node copy-node-contents ( new old -- )
#! copy old's key and value into new (keeping children and parent)
dup node-key pick set-node-key node-value swap set-node-value ;
M: tree create-node ( value key tree -- node ) drop <node> ;
: key-side ( k1 k2 -- side )
#! side is -1 if k1 < k2, 0 if they are equal, or 1 if k1 > k2
<=> sgn ;
: key< ( k1 k2 -- ? ) <=> 0 < ;
: key> ( k1 k2 -- ? ) <=> 0 > ;
: key= ( k1 k2 -- ? ) <=> zero? ;
: random-side ( -- side ) left right 2array random ;
: choose-branch ( key node -- key node-left/right )
2dup node-key key-side [ node-link ] with-side ;
GENERIC: node-get ( key node -- value )
: tree-get ( key tree -- value ) tree-root node-get ;
M: node node-get ( key node -- value )
2dup node-key key= [
nip node-value
] [
choose-branch node-get
] if ;
M: f node-get ( key f -- f ) nip ;
GENERIC: node-get* ( key node -- value ? )
: tree-get* ( key tree -- value ? ) tree-root node-get* ;
M: node node-get* ( key node -- value ? )
2dup node-key key= [
nip node-value t
] [
choose-branch node-get*
] if ;
M: f node-get* ( key f -- f f ) nip f ;
GENERIC: node-get-all ( key node -- seq )
: tree-get-all ( key tree -- seq ) tree-root node-get-all ;
M: f node-get-all ( key f -- V{} ) 2drop V{ } clone ;
M: node node-get-all ( key node -- seq )
2dup node-key key= [
! duplicate keys are stored to the right because of choose-branch
2dup node-right node-get-all >r nip node-value r> tuck push
] [
choose-branch node-get-all
] if ;
GENERIC: node-insert ( value key node -- node ) ! can add duplicates
: tree-insert ( value key tree -- )
[ dup tree-root [ nip node-insert ] [ create-node ] if* ] keep set-tree-root ;
GENERIC: node-set ( value key node -- node )
#! note that this only sets the first node with this key. if more than one
#! has been inserted then the others won't be modified. (should they be deleted?)
: tree-set ( value key tree -- )
[ dup tree-root [ nip node-set ] [ create-node ] if* ] keep set-tree-root ;
GENERIC: node-delete ( key node -- node )
: tree-delete ( key tree -- )
[ tree-root node-delete ] keep set-tree-root ;
GENERIC: node-delete-all ( key node -- node )
M: f node-delete-all ( key f -- f ) nip ;
: tree-delete-all ( key tree -- )
[ tree-root node-delete-all ] keep set-tree-root ;
: node-map-link ( node quot -- node )
over node-link swap call over set-node-link ;
: node-map ( node quot -- node )
over [
tuck [ node-map-link ] go-left over call swap [ node-map-link ] go-right
] [
drop
] if ;
: tree-map ( tree quot -- )
#! apply quot to each element of the tree, in order
over tree-root swap node-map swap set-tree-root ;
: node>node-seq ( node -- seq )
dup [
dup node-left node>node-seq over 1array rot node-right node>node-seq 3append
] when ;
: tree>node-seq ( tree -- seq )
tree-root node>node-seq ;
: tree-keys ( tree -- keys )
tree>node-seq [ node-key ] map ;
: tree-values ( tree -- values )
tree>node-seq [ node-value ] map ;
: leaf? ( node -- ? )
dup node-left swap node-right or not ;
GENERIC: valid-node? ( node -- ? )
M: f valid-node? ( f -- t ) not ;
M: node valid-node? ( node -- ? )
dup dup node-left [ node-key swap node-key key< ] when* >r
dup dup node-right [ node-key swap node-key key> ] when* r> and swap
dup node-left valid-node? swap node-right valid-node? and and ;
: valid-tree? ( tree -- ? ) tree-root valid-node? ;
DEFER: print-tree
: random-tree ( tree size -- tree )
[ most-positive-fixnum random pick tree-set ] each ;
: increasing-tree ( tree size -- tree )
[ dup pick tree-set ] each ;
: decreasing-tree ( tree size -- tree )
reverse increasing-tree ;
GENERIC: print-node ( depth node -- )
M: f print-node ( depth f -- ) 2drop ;
M: node print-node ( depth node -- )
! not pretty, but ok for debugging
over 1+ over node-right print-node
over [ drop " " write ] each dup node-key number>string print
>r 1+ r> node-left print-node ;
: print-tree ( tree -- )
tree-root 1 swap print-node ;
: stump? ( tree -- ? )
#! is this tree empty?
tree-root not ;