英文:
Compare Two trees are equivalent in Golang Using goroutines
问题
不使用通道,我可以比较这两棵树是否相等,但是使用通道时,我无法弄清楚如何做到这一点。
以下是使用通道编写的示例代码:
func Walk(t *Tree, ch chan int) {
if t == nil {
return
}
Walk(t.Left, ch)
ch <- t.Value
Walk(t.Right, ch)
}
func Same(t1, t2 *Tree) bool {
t1Ch := make(chan int)
t2Ch := make(chan int)
Walk(t1, t1Ch)
Walk(t2, t2Ch)
output := make(chan bool)
go func() {
n1 := <-t1Ch
n2 := <-t2Ch
output <- n1 == n2
}()
return <-output
}
func main() {
fmt.Println((&root, &root1))
}
注意:你可以在这里找到完整的描述:https://go.dev/tour/concurrency/7
英文:
Without using channels i am able to compare the two trees are Equivalent or not but with using the channels i am not able to figure it out how to do.
Here is my sample code written using channels.
func Walk(t *Tree, ch chan int) {
if t == nil {
return
}
Walk(t.Left, ch)
ch <- t.Value
Walk(t.Right, ch)
}
func Same(t1, t2 *Tree) bool {
t1Ch := make(chan int)
t2Ch := make(chan int)
Walk(t1, t1Ch)
Walk(t2, t2Ch)
output := make(chan bool)
go func() {
n1 := <-t1Ch
n2 := <-t2Ch
output <- n1 == n2
}()
return <-output
}
func main() {
fmt.Println((&root, &root1))
}
Note:: U can find the full description here https://go.dev/tour/concurrency/7
答案1
得分: 1
我发现了几个问题:
Walk
函数从未关闭通道,这可能导致读取者/接收者一直等待,无限期地阻塞或达到死锁。
我建议在完全遍历树之后关闭通道。
- 在
Same
函数中,你调用了两次Walk
,但第一次调用会无限期地阻塞,因为它将尝试向一个无缓冲通道发送数据(t1Ch := make(chan int)
),而没有人在读取/消费它。
给通道添加缓冲区可能看起来是一个简单的修复方法,但我不建议这样做,因为你无法预测树的大小,所以它是不可靠的,而且你只是把问题推到了后面。
尝试在一个 goroutine 中调用
Walk
,这样你的Same
函数就可以继续执行而不被阻塞。
英文:
A few issues I spotted:
-
The
Walk
function never closes the channel, which might leave readers/receivers waiting for more, blocking indefinitely or reaching a deadlock.
> I'd recommend closing the channel after you are done fully walking the tree. -
In the
Same
function, you callWalk
twice, but the first one will block indefinitely, given that it will try to send stuff to an unbuffered channel (t1Ch := make(chan int)
), and no one is reading/consuming it yet.
> Adding a buffer to the channels might seem like an easy fix but I wouldn't recommend it, you can't predict the size of the tree so it's unreliable, and you would just be kicking the problem down the road.
> Try calling Walk
in a goroutine, so your Same
function can continue unblocked.
答案2
得分: 1
首先,当完成遍历树时,你应该关闭通道。可以通过将递归函数分离出来来实现这一点:
func Walk(t *tree.Tree, ch chan int) {
defer close(ch)
if t != nil {
ch <- t.Value
walkRecursively(t.Left, ch)
walkRecursively(t.Right, ch)
}
}
func walkRecursively(t *tree.Tree, ch chan int) {
if t != nil {
ch <- t.Value
walkRecursively(t.Left, ch)
walkRecursively(t.Right, ch)
}
}
现在,你的Same()
函数可以遍历这两个通道,并知道何时完成工作:
func Same(t1, t2 *tree.Tree) bool {
// 为两棵树创建两个通道
ch1 := make(chan int)
ch2 := make(chan int)
// 两个整数切片用于存储结果
sequence1 := []int{}
sequence2 := []int{}
// 两个 goroutine 将值推送到通道中
// 注意!这些必须是 goroutine
go Walk(t1, ch1)
go Walk(t2, ch2)
// 遍历通道以填充序列变量
for n1 := range ch1 {
sequence1 = append(sequence1, n1)
}
for n2 := range ch2 {
sequence2 = append(sequence2, n2)
}
// 由于树的结构是随机的,我们对序列进行排序
sort.Ints(sequence1)
sort.Ints(sequence2)
// slicesAreEqual 是一个辅助函数
return slicesAreEqual(sequence1, sequence2)
}
你的辅助函数可能如下所示:
func slicesAreEqual(a, b []int) bool {
if len(a) != len(b) {
return false
}
for i, v := range a {
if v != b[i] {
return false
}
}
return true
}
英文:
First of all, you should close your channels when finished walking the tree. This could be accomplished by seperating out your recursive function like so:
func Walk(t *tree.Tree, ch chan int) {
defer close(ch)
if t != nil {
ch <- t.Value
walkRecursively(t.Left, ch)
walkRecursively(t.Right, ch)
}
}
func walkRecursively(t *tree.Tree, ch chan int) {
if t != nil {
ch <- t.Value
walkRecursively(t.Left, ch)
walkRecursively(t.Right, ch)
}
}
Now your Same() function can range over the two channels and know when the work is done:
func Same(t1, t2 *tree.Tree) bool {
// two channels for walking over two trees
ch1 := make(chan int)
ch2 := make(chan int)
// two integer slices to capture two results
sequence1 := []int{}
sequence2 := []int{}
// two go routines to push values to the channels
// IMPORTANT! these must be go routines
go Walk(t1, ch1)
go Walk(t2, ch2)
// range over the channels to populate the sequence vars
for n1 := range ch1 {
sequence1 = append(sequence1, n1)
}
for n2 := range ch2 {
sequence2 = append(sequence2, n2)
}
// since trees are randomly structured, we sort
sort.Ints(sequence1)
sort.Ints(sequence2)
// slicesAreEqual is a helper function
return slicesAreEqual(sequence1, sequence2)
}
Your helper function might look something like this:
func slicesAreEqual(a, b []int) bool {
if len(a) != len(b) {
return false
}
for i, v := range a {
if v != b[i] {
return false
}
}
return true
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论