factor/extra/trees/trees.factor

459 lines
12 KiB
Factor
Raw Normal View History

2009-03-04 17:02:21 -05:00
! Copyright (C) 2007 Alex Chapman
! See http://factorcode.org/license.txt for BSD license.
2014-12-11 23:33:18 -05:00
USING: accessors arrays assocs combinators
combinators.short-circuit deques dlists kernel locals make math
math.order namespaces parser prettyprint.custom random sequences
vectors ;
2009-03-04 17:02:21 -05:00
IN: trees
2010-10-09 14:21:11 -04:00
TUPLE: tree root { count integer } ;
2009-03-04 17:02:21 -05:00
2010-05-04 19:10:34 -04:00
<PRIVATE
2009-03-04 17:02:21 -05:00
: new-tree ( class -- tree )
new
f >>root
0 >>count ; inline
2010-05-04 19:10:34 -04:00
PRIVATE>
2009-03-04 17:02:21 -05:00
: <tree> ( -- tree )
tree new-tree ;
INSTANCE: tree assoc
2010-05-04 19:10:34 -04:00
<PRIVATE
2009-03-04 17:02:21 -05:00
TUPLE: node key value left right ;
: new-node ( key value class -- node )
new
swap >>value
2010-10-09 14:21:11 -04:00
swap >>key ; inline
2009-03-04 17:02:21 -05:00
: <node> ( key value -- node )
node new-node ;
SYMBOL: current-side
CONSTANT: left -1
CONSTANT: right 1
2009-03-04 17:02:21 -05:00
: key-side ( k1 k2 -- n )
<=> {
2014-12-11 23:33:18 -05:00
{ +lt+ [ left ] }
2009-03-04 17:02:21 -05:00
{ +eq+ [ 0 ] }
2014-12-11 23:33:18 -05:00
{ +gt+ [ right ] }
2009-03-04 17:02:21 -05:00
} case ;
: go-left? ( -- ? ) current-side get left eq? ;
: inc-count ( tree -- ) [ 1 + ] change-count drop ;
2009-03-04 17:02:21 -05:00
: dec-count ( tree -- ) [ 1 - ] change-count drop ;
2009-03-04 17:02:21 -05:00
: node-link@ ( node ? -- node )
go-left? xor [ left>> ] [ right>> ] if ;
2014-12-11 23:33:18 -05:00
: set-node-link@ ( left parent ? -- )
go-left? xor [ left<< ] [ right<< ] if ;
2009-03-04 17:02:21 -05:00
: node-link ( node -- child ) f node-link@ ;
2009-03-04 17:02:21 -05:00
: set-node-link ( child node -- ) f set-node-link@ ;
2009-03-04 17:02:21 -05:00
: node+link ( node -- child ) t node-link@ ;
2009-03-04 17:02:21 -05:00
: set-node+link ( child node -- ) t set-node-link@ ;
: with-side ( side quot -- )
2010-05-04 19:10:34 -04:00
[ current-side ] dip with-variable ; inline
2009-03-04 17:02:21 -05:00
: with-other-side ( quot -- )
current-side get neg swap with-side ; inline
2009-03-04 17:02:21 -05:00
: go-left ( quot -- ) left swap with-side ; inline
2009-03-04 17:02:21 -05:00
: go-right ( quot -- ) right swap with-side ; inline
: leaf? ( node -- ? )
2014-12-11 23:33:18 -05:00
{ [ left>> not ] [ right>> not ] } 1&& ;
2009-03-04 17:02:21 -05:00
: random-side ( -- side )
2014-12-11 23:33:18 -05:00
2 random 0 eq? left right ? ;
2009-03-04 17:02:21 -05:00
: choose-branch ( key node -- key node-left/right )
2dup key>> key-side [ node-link ] with-side ;
: node-at* ( key node -- value ? )
[
2dup key>> = [
nip value>> t
] [
choose-branch node-at*
] if
] [ drop f f ] if* ;
2014-12-11 23:33:18 -05:00
M: tree at*
2009-03-04 17:02:21 -05:00
root>> node-at* ;
2017-01-06 10:40:47 -05:00
: node-set ( value key node -- node new? )
2009-03-04 17:02:21 -05:00
2dup key>> key-side dup 0 eq? [
2017-01-06 10:40:47 -05:00
drop nip swap >>value f
2009-03-04 17:02:21 -05:00
] [
[
2017-01-06 10:40:47 -05:00
[ node-link [ node-set ] [ swap <node> t ] if* ] keep
swap [ [ set-node-link ] keep ] dip
2009-03-04 17:02:21 -05:00
] with-side
] if ;
2014-12-11 23:33:18 -05:00
M: tree set-at
2017-01-06 10:40:47 -05:00
[ [ node-set ] [ swap <node> t ] if* swap ] change-root
swap [ dup inc-count ] when drop ;
2009-03-04 17:02:21 -05:00
: valid-node? ( node -- ? )
[
2014-12-11 23:33:18 -05:00
{
[ dup left>> [ key>> swap key>> before? ] when* ]
[ dup right>> [ key>> swap key>> after? ] when* ]
[ left>> valid-node? ]
[ right>> valid-node? ]
} 1&&
2009-03-04 17:02:21 -05:00
] [ t ] if* ;
: valid-tree? ( tree -- ? ) root>> valid-node? ;
: node>entry ( node -- entry ) [ key>> ] [ value>> ] bi 2array ;
: entry, ( node -- ) node>entry , ;
2009-03-04 17:02:21 -05:00
: (node>alist) ( node -- )
[
[ left>> (node>alist) ]
[ entry, ]
2009-03-04 17:02:21 -05:00
[ right>> (node>alist) ]
tri
] when* ;
2014-12-11 23:33:18 -05:00
M: tree >alist
[ root>> (node>alist) ] { } make ;
2009-03-04 17:02:21 -05:00
:: (node>subalist-right) ( to-key node end-comparator: ( key1 key2 -- ? ) -- )
node [
node key>> to-key end-comparator call :> node-left?
node left>> node-left? [ (node>alist) ] [
[ to-key ] dip end-comparator (node>subalist-right)
] if
node-left? [
node [ entry, ] [
right>> [ to-key ] dip
end-comparator (node>subalist-right)
] bi
] when
] when ; inline recursive
:: (node>subalist-left) ( from-key node start-comparator: ( key1 key2 -- ? ) -- )
node [
node key>> from-key start-comparator call :> node-right?
node-right? [
node [
left>> [ from-key ] dip
start-comparator (node>subalist-left)
] [ entry, ] bi
] when
node right>> node-right? [ (node>alist) ] [
[ from-key ] dip start-comparator (node>subalist-left)
] if
] when ; inline recursive
:: (node>subalist) ( from-key to-key node start-comparator: ( key1 key2 -- ? ) end-comparator: ( key1 key2 -- ? ) -- )
node [
node key>> from-key start-comparator call :> node-right?
node key>> to-key end-comparator call :> node-left?
node-right? [
from-key node left>> node-left?
[ start-comparator (node>subalist-left) ]
[
[ to-key ] dip start-comparator
end-comparator (node>subalist)
] if
] when
node-right? node-left? and [ node entry, ] when
node-left? [
to-key node right>> node-right?
[ end-comparator (node>subalist-right) ]
[
[ from-key ] 2dip start-comparator
end-comparator (node>subalist)
] if
] when
] when ; inline recursive
PRIVATE>
: subtree>alist[) ( from-key to-key tree -- alist )
[ root>> [ after=? ] [ before? ] (node>subalist) ] { } make ;
: subtree>alist(] ( from-key to-key tree -- alist )
[ root>> [ after? ] [ before=? ] (node>subalist) ] { } make ;
: subtree>alist[] ( from-key to-key tree -- alist )
[ root>> [ after=? ] [ before=? ] (node>subalist) ] { } make ;
: subtree>alist() ( from-key to-key tree -- alist )
[ root>> [ after? ] [ before? ] (node>subalist) ] { } make ;
: headtree>alist[) ( to-key tree -- alist )
[ root>> [ before? ] (node>subalist-right) ] { } make ;
: headtree>alist[] ( to-key tree -- alist )
[ root>> [ before=? ] (node>subalist-right) ] { } make ;
: tailtree>alist[] ( from-key tree -- alist )
[ root>> [ after=? ] (node>subalist-left) ] { } make ;
: tailtree>alist(] ( from-key tree -- alist )
[ root>> [ after? ] (node>subalist-left) ] { } make ;
<PRIVATE
: (nodepath-at) ( key node -- )
[
dup ,
2dup key>> = [
2drop
] [
choose-branch (nodepath-at)
] if
] [ drop ] if* ;
: nodepath-at ( key tree -- path )
[ root>> (nodepath-at) ] { } make ;
: right-extremity ( node -- node' )
[ dup right>> dup ] [ nip ] while drop ;
: left-extremity ( node -- node' )
[ dup left>> dup ] [ nip ] while drop ;
: lower-node-in-child? ( key node -- ? )
[ nip left>> ] [ key>> = ] 2bi and ;
: higher-node-in-child? ( key node -- ? )
[ nip right>> ] [ key>> = ] 2bi and ;
: lower-node ( key tree -- node )
dupd nodepath-at
[ drop f ] [
reverse 2dup first lower-node-in-child?
[ nip first left>> right-extremity ]
[ [ key>> after? ] with find nip ] if
] if-empty ;
: higher-node ( key tree -- node )
dupd nodepath-at
[ drop f ] [
reverse 2dup first higher-node-in-child?
[ nip first right>> left-extremity ]
[ [ key>> before? ] with find nip ] if
] if-empty ;
: floor-node ( key tree -- node )
dupd nodepath-at [ drop f ] [
reverse [ key>> after=? ] with find nip
] if-empty ;
: ceiling-node ( key tree -- node )
dupd nodepath-at [ drop f ] [
reverse [ key>> before=? ] with find nip
] if-empty ;
: first-node ( tree -- node ) root>> dup [ left-extremity ] when ;
: last-node ( tree -- node ) root>> dup [ right-extremity ] when ;
PRIVATE>
: lower-entry ( key tree -- pair/f ) lower-node dup [ node>entry ] when ;
: higher-entry ( key tree -- pair/f ) higher-node dup [ node>entry ] when ;
: floor-entry ( key tree -- pair/f ) floor-node dup [ node>entry ] when ;
: ceiling-entry ( key tree -- pair/f ) ceiling-node dup [ node>entry ] when ;
: first-entry ( tree -- pair/f ) first-node dup [ node>entry ] when ;
: last-entry ( tree -- pair/f ) last-node dup [ node>entry ] when ;
: lower-key ( key tree -- key/f ) lower-node dup [ key>> ] when ;
: higher-key ( key tree -- key/f ) higher-node dup [ key>> ] when ;
: floor-key ( key tree -- key/f ) floor-node dup [ key>> ] when ;
: ceiling-key ( key tree -- key/f ) ceiling-node dup [ key>> ] when ;
: first-key ( tree -- key/f ) first-node dup [ key>> ] when ;
: last-key ( tree -- key/f ) last-node dup [ key>> ] when ;
<PRIVATE
2009-03-04 17:02:21 -05:00
M: tree clear-assoc
0 >>count
f >>root drop ;
: copy-node-contents ( new old -- new )
[ key>> >>key ]
[ value>> >>value ] bi ;
! Deletion
DEFER: delete-node
: (prune-extremity) ( parent node -- new-extremity )
dup node-link [
2010-05-04 19:10:34 -04:00
[ nip ] dip (prune-extremity)
2009-03-04 17:02:21 -05:00
] [
2017-01-09 11:22:20 -05:00
[ delete-node swap set-node-link ] keep
2009-03-04 17:02:21 -05:00
] if* ;
: prune-extremity ( node -- new-extremity )
2015-09-08 19:15:10 -04:00
! remove and return the leftmost or rightmost child of this node.
! assumes at least one child
2009-03-04 17:02:21 -05:00
dup node-link (prune-extremity) ;
: replace-with-child ( node -- node )
dup node-link copy-node-contents dup node-link delete-node over set-node-link ;
: replace-with-extremity ( node -- node )
dup node-link dup node+link [
! predecessor/successor is not the immediate child
[ prune-extremity ] with-other-side copy-node-contents
] [
! node-link is the predecessor/successor
drop replace-with-child
] if ;
: delete-node-with-two-children ( node -- node )
2015-09-08 19:15:10 -04:00
! randomised to minimise tree unbalancing
2009-03-04 17:02:21 -05:00
random-side [ replace-with-extremity ] with-side ;
: delete-node ( node -- node )
2015-09-08 19:15:10 -04:00
! delete this node, returning its replacement
2014-12-11 23:33:18 -05:00
dup [ right>> ] [ left>> ] bi [
swap [
drop delete-node-with-two-children
2009-03-04 17:02:21 -05:00
] [
2014-12-11 23:33:18 -05:00
nip ! left but no right
2009-03-04 17:02:21 -05:00
] if
] [
2014-12-11 23:33:18 -05:00
nip ! right but no left, or no children
] if* ;
2009-03-04 17:02:21 -05:00
2017-01-06 10:40:47 -05:00
: delete-bst-node ( key node -- node deleted? )
2009-03-04 17:02:21 -05:00
2dup key>> key-side dup 0 eq? [
2017-01-06 10:40:47 -05:00
drop nip delete-node t
2009-03-04 17:02:21 -05:00
] [
2010-05-04 19:10:34 -04:00
[
[ node-link delete-bst-node ]
2017-01-06 10:40:47 -05:00
[ swap [ set-node-link ] dip ]
[ swap ] tri
2010-05-04 19:10:34 -04:00
] with-side
2009-03-04 17:02:21 -05:00
] if ;
M: tree delete-at
2017-01-06 10:40:47 -05:00
[ delete-bst-node swap ] change-root
swap [ dup dec-count ] when drop ;
2009-03-04 17:02:21 -05:00
M: tree new-assoc
2drop <tree> ;
: clone-nodes ( node -- node' )
dup [
clone
[ clone-nodes ] change-left
[ clone-nodes ] change-right
] when ;
M: tree clone (clone) [ clone-nodes ] change-root ;
2009-03-04 17:02:21 -05:00
: ?push-children ( node queue -- )
[ [ left>> ] [ right>> ] bi ]
[ [ over [ push-front ] [ 2drop ] if ] curry bi@ ] bi* ;
: each-bfs-node ( tree quot: ( ... entry -- ... ) -- ... )
[ root>> <dlist> [ push-front ] keep dup ] dip
[
[ drop node>entry ] prepose
[ ?push-children ] 2bi
] 2curry slurp-deque ; inline
: >bfs-alist ( tree -- alist )
dup assoc-size <vector> [
[ push ] curry each-bfs-node
] keep ;
M: tree assoc-clone-like
[ dup tree? [ >bfs-alist ] when ] dip call-next-method ;
2017-01-24 14:03:47 -05:00
PRIVATE>
2009-03-04 17:02:21 -05:00
: >tree ( assoc -- tree )
T{ tree f f 0 } assoc-clone-like ;
SYNTAX: TREE{
\ } [ >tree ] parse-literal ;
2014-12-11 23:33:18 -05:00
2017-01-24 14:03:47 -05:00
<PRIVATE
M: tree assoc-like drop dup tree? [ >tree ] unless ;
2009-03-04 17:02:21 -05:00
M: tree assoc-size count>> ;
M: tree pprint-delims drop \ TREE{ \ } ;
M: tree >pprint-sequence >alist ;
M: tree pprint-narrow? drop t ;
2017-01-06 09:28:24 -05:00
: node-height ( node -- n )
[
[ left>> ] [ right>> ] bi
[ node-height ] bi@ max 1 +
] [ 0 ] if* ;
PRIVATE>
: height ( tree -- n )
root>> node-height ;
2017-01-24 13:59:27 -05:00
<PRIVATE
: pop-tree-extremity ( tree node/f -- node/f )
dup [
[ key>> swap delete-at ] keep node>entry
2017-01-24 13:59:27 -05:00
] [ nip ] if ;
:: slurp-tree ( tree quot: ( ... entry -- ... ) getter: ( tree -- node ) -- ... )
[ tree count>> 0 = ]
[ tree getter call quot call ] until ; inline
2017-01-24 13:59:27 -05:00
PRIVATE>
: pop-tree-left ( tree -- node/f )
dup first-node pop-tree-extremity ;
2017-01-24 13:59:27 -05:00
: pop-tree-right ( tree -- node/f )
dup last-node pop-tree-extremity ;
2017-01-24 13:59:27 -05:00
: slurp-tree-left ( tree quot: ( ... entry -- ... ) -- ... )
[ pop-tree-left ] slurp-tree ; inline
2017-01-24 13:59:27 -05:00
: slurp-tree-right ( tree quot: ( ... entry -- ... ) -- ... )
[ pop-tree-right ] slurp-tree ; inline