Skip to content

Commit a674d1e

Browse files
authored
Add Depth First Search in Tcl (#5047)
1 parent 494aff9 commit a674d1e

File tree

1 file changed

+84
-0
lines changed

1 file changed

+84
-0
lines changed
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package require Tcl 8.6
2+
package require struct ;# for struct::graph
3+
4+
proc usage {} {
5+
puts stderr {Usage: please provide a tree in an adjacency matrix form ("0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0") together with a list of vertex values ("1, 3, 5, 2, 4") and the integer to find ("4")}
6+
exit 1
7+
}
8+
9+
proc isInteger {x} { return [string is integer -strict $x] }
10+
11+
proc parseList {s} {
12+
set s [string trim $s]
13+
if {$s eq ""} { usage }
14+
15+
lmap t [split $s ","] {
16+
set t [string trim $t]
17+
if {![isInteger $t]} { usage }
18+
set t
19+
}
20+
}
21+
22+
proc createGraph {matrix vertices} {
23+
set n [llength $vertices]
24+
if {[llength $matrix] != [expr {$n * $n}]} { usage }
25+
26+
set g [struct::graph]
27+
foreach v $vertices { $g node insert $v }
28+
29+
for {set i 0} {$i < $n} {incr i} {
30+
for {set j 0} {$j < $n} {incr j} {
31+
if {[lindex $matrix [expr {$i*$n + $j}]] != 0} {
32+
set a [lindex $vertices $i]
33+
set b [lindex $vertices $j]
34+
$g arc insert $a $b
35+
}
36+
}
37+
}
38+
return $g
39+
}
40+
41+
proc dfsCommand {target visitedRef foundRef args} {
42+
upvar $visitedRef visited
43+
upvar $foundRef found
44+
45+
set event [lindex $args 0]
46+
set graph [lindex $args 1]
47+
set node [lindex $args 2]
48+
49+
# We're only interested in what happens once we enter a node, not when
50+
# we leave it.
51+
if {$event ne "enter"} { return }
52+
53+
if {[lsearch -exact $visited $node] >= 0} { return }
54+
55+
lappend visited $node
56+
if {$node eq $target} { set found 1 }
57+
}
58+
59+
proc dfs {graph start target} {
60+
set found 0
61+
set visited {}
62+
63+
# Tcllib has DFS directly in struct::graph. However, to use it for this
64+
# I need a callback to tell me whether the target was found. It is quite
65+
# flexible, in typical Tcl fashion, but I don't need it to do very much.
66+
$graph walk $start -type dfs -dir forward \
67+
-command [list dfsCommand $target visited found]
68+
69+
return $found
70+
}
71+
72+
if {$argc != 3} { usage }
73+
74+
set adjMatrix [parseList [lindex $argv 0]]
75+
set vertices [parseList [lindex $argv 1]]
76+
set target [lindex $argv 2]
77+
78+
if {![isInteger $target]} { usage }
79+
80+
set graph [createGraph $adjMatrix $vertices]
81+
set root [lindex $vertices 0]
82+
83+
puts [expr {[dfs $graph $root $target] ? "true" : "false"}]
84+

0 commit comments

Comments
 (0)