Tarjan: Difference between revisions
Content added Content deleted
(+Racket) |
|||
Line 486: | Line 486: | ||
{4,5} |
{4,5} |
||
{8} |
{8} |
||
</pre> |
|||
=={{header|Racket}}== |
|||
{{trans|Kotlin}} |
|||
<lang racket>#lang racket |
|||
(require syntax/parse/define |
|||
fancy-app |
|||
(for-syntax racket/syntax)) |
|||
(struct node (name index low-link on?) #:transparent #:mutable |
|||
#:methods gen:custom-write |
|||
[(define (write-proc v port mode) (fprintf port "~a" (node-name v)))]) |
|||
(define-syntax-parser change! |
|||
[(_ x:id f) #'(set! x (f x))] |
|||
[(_ accessor:id v f) |
|||
#:with mutator! (format-id this-syntax "set-~a!" #'accessor) |
|||
#'(mutator! v (f (accessor v)))]) |
|||
(define (tarjan g) |
|||
(define sccs '()) |
|||
(define index 0) |
|||
(define s '()) |
|||
(define (dfs v) |
|||
(set-node-index! v index) |
|||
(set-node-low-link! v index) |
|||
(set-node-on?! v #t) |
|||
(change! s (cons v _)) |
|||
(change! index add1) |
|||
(for ([w (in-list (hash-ref g v '()))]) |
|||
(match-define (node _ index low-link on?) w) |
|||
(cond |
|||
[(not index) (dfs w) |
|||
(change! node-low-link v (min (node-low-link w) _))] |
|||
[on? (change! node-low-link v (min low-link _))])) |
|||
(when (= (node-low-link v) (node-index v)) |
|||
(define-values (scc* s*) (splitf-at s (λ (w) (not (eq? w v))))) |
|||
(set! s (rest s*)) |
|||
(define scc (cons (first s*) scc*)) |
|||
(for ([w (in-list scc)]) (set-node-on?! w #f)) |
|||
(change! sccs (cons scc _)))) |
|||
(for* ([(u vs) (in-hash g)] |
|||
[w (in-list (cons u vs))] |
|||
#:when (not (node-index w))) (dfs w)) |
|||
sccs) |
|||
(define (make-graph h) |
|||
(define store (make-hash)) |
|||
(define (make-node v) (hash-ref! store v (thunk (node v #f #f #f)))) |
|||
;; it's important that we use hasheq instead of hash so that we compare |
|||
;; reference instead of actual value. Had we use the actual value, |
|||
;; the key would be a mutable value, which causes undefined behavior |
|||
(for/hasheq ([(u vs) (in-hash h)]) (values (make-node u) (map make-node vs)))) |
|||
(tarjan (make-graph #hash([0 . (1)] |
|||
[2 . (0)] |
|||
[5 . (2 6)] |
|||
[6 . (5)] |
|||
[1 . (2)] |
|||
[3 . (1 2 4)] |
|||
[4 . (5 3)] |
|||
[7 . (4 7 6)])))</lang> |
|||
{{out}} |
|||
<pre> |
|||
'((7) (3 4) (5 6) (2 1 0)) |
|||
</pre> |
</pre> |
||