For more information including compatibility, examples and test cases, see https://github.com/petercrlane/r7rs-libs
1. Disjoint Set: (import (robin disjoint-set))
A disjoint-set data structure holds items in distinct sets (or groups). Efficient procedures are provided for finding a representative of the set any item is contained in, and also for joining two sets together.
1.1. make-disjoint-set
make-disjoint-set
takes two parameters: the equality function to use on
terms, and a hash function (e.g. SRFI 69’s hash
, string-hash
or hash-by-identity
).
The return value is a disjoint set.
1.2. disjoint-set?
disjoint-set?
checks if its argument is a disjoint-set instance or not, returning a boolean value.
1.3. disjoint-set:make
disjoint-set:make
places an item into the disjoint-set as its own group.
Takes two arguments: the disjoint set and the item. Return value is undefined.
1.4. disjoint-set:find
disjoint-set:find
takes two arguments, the disjoint set and an item, and an
optional default value. The function returns the representative item for the group that
the given item is in, or the default value if not present (default is 'item-not-found
if not provided).
1.5. disjoint-set:union
disjoint-set:union
takes three arguments, the disjoint set and two items. The
disjoint set is modified to combine the groups that the two items are in.
1.6. disjoint-set:size
disjoint-set:size
takes a disjoint set and returns the number of
distinct groups it contains.
1.7. Example: Kruskal’s Algorithm
This example illustrates how disjoint sets can be used in Kruskal’s algorithm to find a minimal spanning set. (The complete code is in "robin-examples/kruskal.sps")
(define (kruskal graph) (let ((result '()) (nodes (delete-duplicates (append (map car graph) (map cadr graph)) eq?))) ; 1. make a disjoint set, with each node an item (let ((ds (make-disjoint-set eq? hash-by-identity))) ; <1> (for-each (lambda (node) (disjoint-set:make ds node)) ; <2> nodes) ; 2. set 'links' holds all the links in graph, sorted with the shortest first (let loop ((links (sort graph (lambda (a b) (< (caddr a) (caddr b)))))) ; 3. if links non-empty and size > 1 (when (and (not (null? links)) (> (disjoint-set:size ds) 1)) ; <3> (let ((link (car links))) (unless (eq? (disjoint-set:find ds (car link)) ; <4> (disjoint-set:find ds (cadr link))) (set! result (cons link result)) (disjoint-set:union ds (car link) (cadr link)))) ; <5> (loop (cdr links))))) (reverse result))) ;; using it (let* ((graph '((a b 3) (a e 1) (b c 5) (b e 4) (c d 2) (c e 6) (d e 7))) (res (kruskal graph))) (format #t "MST has ~a links~&" (length res)) (format #t "~{ : ~a~&~}" res) ; <6> (format #t "Total length: ~a~&" (fold + 0 (map caddr res))))
-
Creates a disjoint set using
eq?
for equality andhash-by-identity
for the hash function, because individual items are symbols. -
Each node is added to the disjoint set, initially in its own group.
-
The number of groups in the disjoint set tells us how many links remain to be added.
-
Look for a link where its end points are in different groups: tested by finding the representative item of each end point’s group in the disjoint set.
-
When we add a link, connect the groups in the disjoint set.
-
Note use of
format
to print a list of items
Output:
MST has 4 links
: (a e 1)
: (c d 2)
: (a b 3)
: (b c 5)
Total length: 11