我正在尝试使用 DFS 通过检查图中每个节点的循环来检查循环图。
我想为每个节点运行一个 goroutine,并在检测到第一个循环或没有循环时终止。
在检测到第一个周期时终止似乎很好,但我无法将其与不再有节点的情况混合使用。
下面是一个似乎有效的实现,但对我来说看起来很糟糕,我一直在寻找更好的实现。我基本上使用缓冲通道并在每次我没有得到一个循环时递增一个计数器,并在计数器达到底层图形的大小时终止。
使用计数器来确定我们何时完成对我来说似乎不合时宜。或者,更确切地说,很高兴知道在 Go 中是否有更惯用的方法来执行此操作。
func (c *cycleDet) hasCycle() bool {
adj := c.b // adjacency list representation of the unerlying graph
hasCycles := make(chan bool, len(adj))
for node := range adj {
go func(no nodeID, co chan<- bool) {
visited := make(map[nodeID]struct{})
// c.nodeHasCycle will use a recursive implementation of DFS to
// find out if the node no leads to a cycle.
if c.nodeHasCycle(no, visited) {
co <- true
return
}
co <- false
}(node, hasCycles)
}
var i int
for {
select {
case v := <-hasCycles:
if v {
fmt.Println("got cycle")
return true
}
if i == len(c.b) {
return false
}
i++
}
}
}
我还遇到了另一个推荐使用“观察者”goroutine 的 SO 帖子(尽管我找不到 SO 帖子)。我不确定那会是什么样子,但想象一下它会WaitGroup像这样与 s 混合:
func (c *cycleDet) hasCycle() bool {
hasCycle := make(chan bool)
done := make(chan struct{})
var wg sync.WaitGroup
adj := c.b // adjacency list representation of the unerlying graph
for node := range adj {
go func(no nodeID, co chan<- bool) {
// Use wg to synchronize termination of read-only goroutines.
wg.Add(1)
defer wg.Done()
visited := make(map[nodeID]struct{})
// c.nodeHasCycle will use a recursive implementation of DFS to
// find out if the node no leads to a cycle.
if c.nodeHasCycle(no, visited) {
co <- true
return
}
}(node, hasCycle)
}
然而,这种方法让我担心,因为我需要睡觉让观察者只在第一个WaitGroup计数器递增后才开始等待,这似乎比第一个解决方案脆弱得多。
HUH函数
相关分类