Go Tour练习#7:二叉树的等价性

huangapple go评论82阅读模式
英文:

Go Tour Exercise #7: Binary Trees equivalence

问题

我正在尝试解决Go Tour上的等价二叉树练习。这是我所做的:

package main

import "tour/tree"
import "fmt"

// Walk遍历树t,将所有值发送到通道ch。
func Walk(t *tree.Tree, ch chan int) {
    if t.Left != nil {
        Walk(t.Left, ch)
    }
    ch <- t.Value
    if t.Right != nil {
        Walk(t.Right, ch)
    }
}

// Same确定树t1和t2是否包含相同的值。
func Same(t1, t2 *tree.Tree) bool {
    ch1 := make(chan int)
    ch2 := make(chan int)
    go Walk(t1, ch1)
    go Walk(t2, ch2)
    for k := range ch1 {
        select {
        case g := <-ch2:
            if k != g {
                return false
            }
        default:
            break
        }
    }
    return true
}

func main() {
    fmt.Println(Same(tree.New(1), tree.New(1)))
    fmt.Println(Same(tree.New(1), tree.New(2)))
}

然而,我无法找到如何在树中没有更多元素时发出信号的方法。我不能在Walk()上使用close(ch),因为它会在所有值都发送之前关闭通道(因为递归的原因)。有人可以帮帮我吗?

英文:

I am trying to solve equivalent binary trees exercise on go tour. Here is what I did;

package main

import &quot;tour/tree&quot;
import &quot;fmt&quot;

// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
	if t.Left != nil {
		Walk(t.Left, ch)
	}
	ch &lt;- t.Value
	if t.Right != nil {
		Walk(t.Right, ch)
	}

}

// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
	ch1 := make(chan int)
	ch2 := make(chan int)
	go Walk(t1, ch1)
	go Walk(t2, ch2)
	for k := range ch1 {
		select {
		case g := &lt;-ch2:
			if k != g {
				return false
			}
		default:
			break
		}
	}
	return true
}

func main() {
	fmt.Println(Same(tree.New(1), tree.New(1)))
	fmt.Println(Same(tree.New(1), tree.New(2)))
}

However, I couldn't find out how to signal if any no more elements left in trees. I can't use close(ch) on Walk() because it makes the channel close before all values are sent (because of recursion.) Can anyone lend me a hand here?

答案1

得分: 137

golang-nuts group中提出了一个使用closure的优雅解决方案,

func Walk(t *tree.Tree, ch chan int) {
	defer close(ch) // &lt;- 当这个函数返回时关闭通道
	var walk func(t *tree.Tree)
	walk = func(t *tree.Tree) {
		if t == nil {
			return
		}
		walk(t.Left)
		ch &lt;- t.Value
		walk(t.Right)
	}
	walk(t)
}
英文:

An elegant solution using closure was presented in the golang-nuts group,

func Walk(t *tree.Tree, ch chan int) {
	defer close(ch) // &lt;- closes the channel when this function returns
	var walk func(t *tree.Tree)
	walk = func(t *tree.Tree) {
		if t == nil {
			return
		}
		walk(t.Left)
		ch &lt;- t.Value
		walk(t.Right)
	}
	walk(t)
}

答案2

得分: 44

这是使用这里的想法和Google Group主题的完整解决方案

package main

import "fmt"
import "code.google.com/p/go-tour/tree"

// Walk遍历树t,将树中的所有值发送到通道ch。
func Walk(t *tree.Tree, ch chan int) {
    var walker func(t *tree.Tree)
    walker = func (t *tree.Tree) {
        if (t == nil) {
            return
        }
        walker(t.Left)
        ch <- t.Value
        walker(t.Right)
    }
    walker(t)
    close(ch)
}

// Same确定树t1和t2是否包含相同的值。
func Same(t1, t2 *tree.Tree) bool {
    ch1, ch2 := make(chan int), make(chan int)
    
    go Walk(t1, ch1)
    go Walk(t2, ch2)
    
    for {
        v1,ok1 := <- ch1
        v2,ok2 := <- ch2
        
        if v1 != v2 || ok1 != ok2 {
            return false
        }
        
        if !ok1 {
            break
        }
    }
    
    return true
}

func main() {
    fmt.Println("1 and 1 same: ", Same(tree.New(1), tree.New(1)))
    fmt.Println("1 and 2 same: ", Same(tree.New(1), tree.New(2)))
    
}
英文:

Here's the full solution using ideas here and from the Google Group thread

package main

import &quot;fmt&quot;
import &quot;code.google.com/p/go-tour/tree&quot;

// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
    var walker func(t *tree.Tree)
    walker = func (t *tree.Tree) {
        if (t == nil) {
            return
        }
        walker(t.Left)
        ch &lt;- t.Value
        walker(t.Right)
    }
	walker(t)
    close(ch)
}

// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
	ch1, ch2 := make(chan int), make(chan int)
    
    go Walk(t1, ch1)
    go Walk(t2, ch2)
    
    for {
        v1,ok1 := &lt;- ch1
        v2,ok2 := &lt;- ch2
        
        if v1 != v2 || ok1 != ok2 {
            return false
        }
        
        if !ok1 {
            break
        }
    }
    
    return true
}

func main() {
    fmt.Println(&quot;1 and 1 same: &quot;, Same(tree.New(1), tree.New(1)))
    fmt.Println(&quot;1 and 2 same: &quot;, Same(tree.New(1), tree.New(2)))
    
}

答案3

得分: 34

你可以在Walk函数不递归调用自身时使用close()。也就是说,Walk函数只需要这样做:

func Walk(t *tree.Tree, ch chan int) {
    walkRecurse(t, ch)
    close(ch)
}

其中walkRecurse函数更多或更少地是你当前的Walk函数,但是在walkRecurse上进行递归。
(或者你可以重写Walk函数为迭代方式 - 这可能更麻烦)
使用这种方法,你的Same()函数必须知道通道已经关闭,可以通过以下形式的通道接收来完成:

k, ok1 := <-ch
g, ok2 := <-ch

ok1ok2不同时,或者当它们都为false时,采取适当的操作。

另一种方法,但可能不符合练习的要求,是计算树中节点的数量:

func Same(t1, t2 *tree.Tree) bool {
    countT1 := countTreeNodes(t1)
    countT2 := countTreeNodes(t2)
    if countT1 != countT2 {
        return false
    }
    ch1 := make(chan int)
    ch2 := make(chan int)
    go Walk(t1, ch1)
    go Walk(t2, ch2)
    for i := 0; i < countT1; i++ {
        if <-ch1 != <-ch2 {
            return false
        }
    }
    return true
}

你需要实现countTreeNodes()函数,该函数应该计算*Tree中节点的数量。

英文:

You could use close() if your Walk function doesn't recurse on itself. i.e. Walk would just do:

func Walk(t *tree.Tree, ch chan int) {
    walkRecurse(t, ch)
    close(ch)
}

Where walkRecurse is more or less your current Walk function, but recursing on walkRecurse.
(or you rewrite Walk to be iterative - which, granted, is more hassle)
With this approach, your Same() function have to learn that the channels was closed, which is done with the channel receive of the form

k, ok1 := &lt;-ch
g, ok2 := &lt;-ch

And take proper action when ok1 and ok2 are different, or when they're both false

Another way, but probably not in the spirit of the exercise, is to count the number of nodes in the tree:

func Same(t1, t2 *tree.Tree) bool {
	countT1 := countTreeNodes(t1)
	countT2 := countTreeNodes(t2)
	if countT1 != countT2 {
		return false
	}
	ch1 := make(chan int)
	ch2 := make(chan int)
	go Walk(t1, ch1)
	go Walk(t2, ch2)
	for i := 0; i &lt; countT1; i++ {
		if &lt;-ch1 != &lt;-ch2 {
			return false
		}
	}
	return true
}

You'll have to implement the countTreeNodes() function, which should count the number of nodes in a *Tree

答案4

得分: 20

这是我是如何做到的,不同之处在于你可以将Walk包装成匿名函数,并在其中使用defer close(ch)。因此,你不需要定义其他命名的递归函数。

package main

import (
	"golang.org/x/tour/tree"
	"fmt"
)
// Walk遍历树t,将树中的所有值发送到通道ch。
func Walk(t *tree.Tree, ch chan int) {
    if t == nil {
        return
    }
    Walk(t.Left, ch)
	ch <- t.Value
    Walk(t.Right, ch)
}
// Same确定树t1和t2是否包含相同的值。
func Same(t1, t2 *tree.Tree) bool {
	ch1, ch2 := make(chan int), make(chan int)
	go func() {
		defer close(ch1)
		Walk(t1, ch1)
	}()
	go func() {
		defer close(ch2)
		Walk(t2, ch2)
	}()
	for {
		v1, ok1 := <- ch1
		v2, ok2 := <- ch2
		if ok1 != ok2 || v1 != v2 {
			return false
		}
		if !ok1 && !ok2 {
			break
		}
	}
	return true
}

func main() {
	ch := make(chan int)
	go func () {
		defer close(ch)
		Walk(tree.New(3), ch)
	}()
	for i := range ch {
		fmt.Println(i)
	}
	
	fmt.Println(Same(tree.New(1), tree.New(1)))
	fmt.Println(Same(tree.New(1), tree.New(2)))
	fmt.Println(Same(tree.New(10), tree.New(10)))
}
英文:

This is how I did it, the difference is that you can wrap Walk into anonymous function and defer close(ch) inside it. Thus you have not to define other named recursive function

package main
import (
&quot;golang.org/x/tour/tree&quot;
&quot;fmt&quot;
)
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
if t == nil {
return
}
Walk(t.Left, ch)
ch &lt;- t.Value
Walk(t.Right, ch)
}
// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
ch1, ch2 := make(chan int), make(chan int)
go func() {
defer close(ch1)
Walk(t1, ch1)
}()
go func() {
defer close(ch2)
Walk(t2, ch2)
}()
for {
v1, ok1 := &lt;- ch1
v2, ok2 := &lt;- ch2
if ok1 != ok2 || v1 != v2 {
return false
}
if !ok1 &amp;&amp; !ok2 {
break
}
}
return true
}
func main() {
ch := make(chan int)
go func () {
defer close(ch)
Walk(tree.New(3), ch)
}()
for i := range ch {
fmt.Println(i)
}
fmt.Println(Same(tree.New(1), tree.New(1)))
fmt.Println(Same(tree.New(1), tree.New(2)))
fmt.Println(Same(tree.New(10), tree.New(10)))
}

答案5

得分: 9

尽管我的第一直觉是将递归遍历和关闭通道也包装起来,但我觉得这不符合练习的精神。

练习文本包含以下信息:

函数tree.New(k)构造一个随机结构(但始终排序)的二叉树,其中包含值k, 2k, 3k, ..., 10k

这明确说明生成的树恰好有10个节点。

因此,在这个练习的精神和简单性中,我选择了以下解决方案:

package main

import (
	"fmt"
	"golang.org/x/tour/tree"
)

func Walk(t *tree.Tree, ch chan int) {
	if t.Left != nil {
		Walk(t.Left, ch)
	}
	ch <- t.Value
	if t.Right != nil {
		Walk(t.Right, ch)
	}
}

func Same(t1, t2 *tree.Tree) bool {
	ch1 := make(chan int)
	ch2 := make(chan int)

	defer close(ch1)
	defer close(ch2)

	go Walk(t1, ch1)
	go Walk(t2, ch2)
	
	for i := 0; i < 10; i++ {
		if <-ch1 != <-ch2 {
			return false
		}
	}

	return true
}

func main() {
	fmt.Println(Same(tree.New(1), tree.New(2)))
}

如果目标是在任意大小的树上运行,则对关闭的通道做出反应是更好的解决方案,但我觉得这是一个简单的练习,故意设置了限制,以便让新的Gopher更容易理解。

英文:

While my first intuition was to also wrap the recursive walk and closing the channels, I felt it was not in the spirit of the exercise.

The exercise text contains the following information:

> The function tree.New(k) constructs a randomly-structured (but always sorted) binary tree holding the values k, 2k, 3k, ..., 10k.

Which clearly states that the resulting trees have exactly 10 nodes.

Therefore, in the spirit and simplicity of this exercise, I went with the following solution:

package main
import (
&quot;fmt&quot;
&quot;golang.org/x/tour/tree&quot;
)
func Walk(t *tree.Tree, ch chan int) {
if t.Left != nil {
Walk(t.Left, ch)
}
ch &lt;- t.Value
if t.Right != nil {
Walk(t.Right, ch)
}
}
func Same(t1, t2 *tree.Tree) bool {
ch1 := make(chan int)
ch2 := make(chan int)
defer close(ch1)
defer close(ch2)
go Walk(t1, ch1)
go Walk(t2, ch2)
for i := 0; i &lt; 10; i++ {
if &lt;-ch1 != &lt;-ch2 {
return false
}
}
return true
}
func main() {
fmt.Println(Same(tree.New(1), tree.New(2)))
}

If the goal would be to run on arbitrarily sized trees, then reacting to closed channels is the better solution, but I felt this was a simple exercise with intentionally put constraints to make it easier for the new Gopher.

答案6

得分: 9

这是我的解决方案。

package main

import (
  "golang.org/x/tour/tree"
  "fmt"
)

// Walk函数遍历树t,将树中的所有值发送到通道ch。
func Walk(t *tree.Tree, ch chan int) {
	if t == nil {
		return
	}
	
	Walk(t.Left, ch)
	ch <- t.Value
	Walk(t.Right, ch)
}

// Same函数确定树t1和t2是否包含相同的值。
func Same(t1, t2 *tree.Tree) bool {
	ch1,ch2 := make(chan int),make(chan int)
	
	go func() {
		Walk(t1, ch1)
		close(ch1)
	}()
	
	go func() {
		Walk(t2, ch2)
		close(ch2)
	}()
	
	for {
		v1, ok1 := <- ch1
		v2, ok2 := <- ch2
		
		if ok1 == false && ok2 == false {
			return true
		}
		
		if v1 != v2 {
			return false
		}
	}

	return false
}

func main() {
	fmt.Println(Same(tree.New(1), tree.New(1)))	
	fmt.Println(Same(tree.New(1), tree.New(2)))	
}

英文:

This is my solution.

package main

import (
  &quot;golang.org/x/tour/tree&quot;
  &quot;fmt&quot;
)

// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
	if t == nil {
		return
	}
	
	Walk(t.Left, ch)
	ch &lt;- t.Value
	Walk(t.Right, ch)
}

// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
	ch1,ch2 := make(chan int),make(chan int)
	
	go func() {
		Walk(t1, ch1)
		close(ch1)
	}()
	
	go func() {
		Walk(t2, ch2)
		close(ch2)
	}()
	
	for {
		v1, ok1 := &lt;- ch1
		v2, ok2 := &lt;- ch2
		
		if ok1 == false &amp;&amp; ok2 == false {
			return true
		}
		
		if v1 != v2 {
			return false
		}
	}

	return false
}

func main() {
	fmt.Println(Same(tree.New(1), tree.New(1)))	
	fmt.Println(Same(tree.New(1), tree.New(2)))	
}

答案7

得分: 5

使用匿名函数和goroutine

go func() {
.... // 逻辑
close(ch) // 最后关闭通道或延迟关闭通道
// 不要在goroutine外部使用close()
}()

以下是易于阅读的代码

Walk函数

func Walk(t *tree.Tree, ch chan int) {
if t.Left != nil {
Walk(t.Left, ch)
}
ch <- t.Value
if t.Right != nil {
Walk(t.Right, ch)
}
}

同样的函数

func Same(t1, t2 *tree.Tree) bool {
ch1 := make(chan int)
ch2 := make(chan int)
go func() {
Walk(t1, ch1)
close(ch1)
}()
go func() {
Walk(t2, ch2)
close(ch2)
}()
for {
v1, ok1 := <-ch1
v2, ok2 := <-ch2
if !ok1 && !ok2 {
// 两个通道同时关闭(且到目前为止所有的值都相等)
return true
}
if !ok1 || !ok2 || v1 != v2 {
return false
}
}
return true
}

main函数

func main() {
c := make(chan int)
t1 := tree.New(1)
go func() {
Walk(t1, c)
close(c)
}()
for i := range c {
fmt.Print(i) // 12345678910
}
fmt.Println("")
result1 := Same(tree.New(1), tree.New(1))
fmt.Println(result1) // true
result2 := Same(tree.New(1), tree.New(2))
fmt.Println(result2) // false
}
英文:

Use goroutine with an anonymous function

go func() {
.... // logic
close(ch)// last close channel or defer close channel
// do not use close() outside of goroutine
}()

Here's code which can read easy

Walk func

func Walk(t *tree.Tree, ch chan int) {
if t.Left != nil {
Walk(t.Left, ch)
}
ch &lt;- t.Value
if t.Right != nil {
Walk(t.Right, ch)
}
}

Same func

func Same(t1, t2 *tree.Tree) bool {
ch1 := make(chan int)
ch2 := make(chan int)
go func() {
Walk(t1, ch1)
close(ch1)
}()
}()
go func() {
Walk(t2, ch2)
close(ch2)
}()
}()
for {
v1, ok1 := &lt;- ch1
v2, ok2 := &lt;- ch2
if !ok1 &amp;&amp; !ok2 {
// both closed at the same time (and all values until now were equal)
return true
}
if !ok1 || !ok2 || v1 != v2 {
return false
}
}
return true
}

main func

func main() {
c := make(chan int)
t1 := tree.New(1)
go func() {
Walk(t1, c)
close(c)
}()
for i := range c {
fmt.Print(i) // 12345678910
}
fmt.Println(&quot;&quot;)
result1 := Same(tree.New(1), tree.New(1))
fmt.Println(result1) // true
result2 := Same(tree.New(1), tree.New(2))
fmt.Println(result2) // false
}

答案8

得分: 4

这是我的解决方案。它正确地检查了两个序列长度的差异。

package main
import "code.google.com/p/go-tour/tree"
import "fmt"
func Walk(t *tree.Tree, ch chan int) {
var walker func (t *tree.Tree)
walker = func (t *tree.Tree) {
if t.Left != nil {
walker(t.Left)
}
ch <- t.Value
if t.Right != nil {
walker(t.Right)
}
}
walker(t)
close(ch)
}
func Same(t1, t2 *tree.Tree) bool {
chana := make (chan int)
chanb := make (chan int)
go Walk(t1, chana)
go Walk(t2, chanb)
for {
n1, ok1 := <-chana
n2, ok2 := <-chanb        
if n1 != n2 || ok1 != ok2 {
return false
}
if (!ok1) {
break
}
}
return true; 
}
英文:

This is my solution. It properly checks for differences in the length of the two sequences.

package main
import &quot;code.google.com/p/go-tour/tree&quot;
import &quot;fmt&quot;
func Walk(t *tree.Tree, ch chan int) {
var walker func (t *tree.Tree)
walker = func (t *tree.Tree) {
if t.Left != nil {
walker(t.Left)
}
ch &lt;- t.Value
if t.Right != nil {
walker(t.Right)
}
}
walker(t)
close(ch)
}
func Same(t1, t2 *tree.Tree) bool {
chana := make (chan int)
chanb := make (chan int)
go Walk(t1, chana)
go Walk(t2, chanb)
for {
n1, ok1 := &lt;-chana
n2, ok2 := &lt;-chanb        
if n1 != n2 || ok1 != ok2 {
return false
}
if (!ok1) {
break
}
}
return true; 
}

答案9

得分: 3

你几乎翻译得很对,没有必要使用select语句,因为你会经常通过default情况,这是我的解决方案,它可以在不需要计算树中节点数的情况下工作:

func Same(t1, t2 *tree.Tree) bool {
    ch1, ch2 := make(chan int), make(chan int)
    go Walk(t1, ch1)
    go Walk(t2, ch2)
    for i := range ch1 {
        j, more := <-ch2
        if more {
            if i != j { return false }
        } else { return false }
    }

    return true
}
英文:

You got it almost right, there's no need to use the select statement because you will go through the default case too often, here's my solution that works without needing to count the number of nodes in the tress:

func Same(t1, t2 *tree.Tree) bool {
ch1, ch2 := make(chan int), make(chan int)
go Walk(t1, ch1)
go Walk(t2, ch2)
for i := range ch1 {
j, more := &lt;-ch2
if more {
if i != j { return false }
} else { return false }
}
return true
}

答案10

得分: 2

所有之前的答案都没有解决关于Same函数的任务。问题是:

// Same determines whether the trees
// t1 and t2 contain the same values.
func Same2(t1, t2 *tree.Tree) bool

它不应该考虑树的结构。这就是为什么以下测试失败,两行都返回false:

fmt.Println("Should return true:", Same(tree.New(1), tree.New(1)))
fmt.Println("Should return false:", Same(tree.New(1), tree.New(2)))

还记得吗?

函数tree.New(k)构造一个随机结构(但始终排序)的二叉树,其中包含值k,2k,3k,...,10k。

你只需要检查两个树是否具有相同的值。任务描述明确指出:

Same(tree.New(1), tree.New(1))应返回trueSame(tree.New(1), tree.New(2))应返回false

因此,为了解决这个任务,你需要缓存第一个树的所有结果,并检查第二个树的值是否在第一个树中。

这是我的解决方案,它不是理想的 Go Tour练习#7:二叉树的等价性

// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
ch1, ch2 := make(chan int), make(chan int)
go Walk(t1, ch1)
go Walk(t2, ch2)
var tv1 = []int{}
for v := range ch1 {
tv1 = append(tv1, v)
}
inArray := func(arr []int, value int) bool {
for a := range arr {
if arr[a] == value {
return true
}
}
return false
}
for v2 := range ch2 {
if !inArray(tv1, v2) {
return false
}
}
return true
}
英文:

All of previous answers do not solve the task about Same function. The question is:

// Same determines whether the trees
// t1 and t2 contain the same values.
func Same2(t1, t2 *tree.Tree) bool

It shouldn't consider structure of tree. That's why following tests fail, gives us false in both lines:

fmt.Println(&quot;Should return true:&quot;, Same(tree.New(1), tree.New(1)))
fmt.Println(&quot;Should return false:&quot;, Same(tree.New(1), tree.New(2)))

Remember?
> The function tree.New(k) constructs a randomly-structured (but always sorted) binary tree holding the values k, 2k, 3k, ..., 10k.

You need just check that both trees have the same values. And task description clearly notice that:

Same(tree.New(1), tree.New(1)) should return true, and Same(tree.New(1), tree.New(2)) should return false.

So to solve the task you need buffer all results from one tree and check does the values from second tree are in the first one.

Here is my solution, it's not ideal one Go Tour练习#7:二叉树的等价性 :

// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
ch1, ch2 := make(chan int), make(chan int)
go Walk(t1, ch1)
go Walk(t2, ch2)
var tv1 = []int{}
for v := range ch1 {
tv1 = append(tv1, v)
}
inArray := func(arr []int, value int) bool {
for a := range arr {
if arr[a] == value {
return true
}
}
return false
}
for v2 := range ch2 {
if !inArray(tv1, v2) {
return false
}
}
return true
}

答案11

得分: 2

package main

import (
"fmt"
"golang.org/x/tour/tree"
)

// Walk遍历树t,将所有值发送到通道ch。
func Walk(t *tree.Tree, ch chan int) {
if t != nil {
Walk(t.Left, ch)
ch <- t.Value
Walk(t.Right, ch)
}
}

// Same确定树t1和t2是否包含相同的值。
func Same(t1, t2 *tree.Tree) bool {
ch1, ch2 := make(chan int), make(chan int)
go func() { Walk(t1, ch1); close(ch1) }()
go func() { Walk(t2, ch2); close(ch2) }()
for v1 := range ch1 {
if v1 != <-ch2 {
return false
}
}
return true
}

func main() {
fmt.Println(Same(tree.New(1), tree.New(1)))
fmt.Println(Same(tree.New(2), tree.New(1)))
}

英文:
package main
import (
&quot;fmt&quot;
&quot;golang.org/x/tour/tree&quot;
)
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
if t != nil {
Walk(t.Left, ch)
ch &lt;- t.Value
Walk(t.Right, ch)
}
}
// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
ch1, ch2 := make(chan int), make(chan int)
go func() { Walk(t1, ch1); close(ch1) }()
go func() { Walk(t2, ch2); close(ch2) }()
for v1 := range ch1 {
if v1 != &lt;-ch2 {
return false
}
}
return true
}
func main() {
fmt.Println(Same(tree.New(1), tree.New(1)))
fmt.Println(Same(tree.New(2), tree.New(1)))
}

答案12

得分: 1

尝试使用映射结构解决这个问题。

func Same(t1, t2 *tree.Tree) bool {
countMap := make(map[int]int)
ch := make(chan int)
go Walk(t1, ch)
for v := range ch {
countMap[v]++
}
ch = make(chan int)
go Walk(t2, ch)
for v := range ch {
countMap[v]--
if countMap[v] < 0 {
return false
}
}
return true
}
英文:

Tried to solve this problem using map structure.

func Same(t1, t2 *tree.Tree) bool {
countMap := make(map[int]int)
ch := make(chan int)
go Walk(t1, ch)
for v := range ch {
countMap[v]++
}
ch = make(chan int)
go Walk(t2, ch)
for v := range ch {
countMap[v]--
if countMap[v] &lt; 0 {
return false
}
}
return true
}

答案13

得分: 1

这里有一个非递归的解决方案(即在大输入上不会有堆栈空间问题),它也不需要一个单独的visited map - 它只使用一个单一的Stack数据结构。避免visited map的技巧是从堆栈中删除visited条目,而是为visited条目创建新的tree.Tree实例,其中左侧被删除,以便不会重新访问左侧。

输出结果是:

1 2 3 4 5 6 7 8 9 10 
1 2 
1 and 2 same (false):  false
1 and 1 same (true):  true
empty same (true):  true
diff length same (false):  false
英文:

Here's a non-recursive solution (i.e. won't have stack space issues on large inputs) that also does not require a separate visited map - it just uses a single Stack data structure. The trick to avoiding a visited map is to remove the visited entries from the stack and instead create new tree.Tree instances for the visited entries, with the Left side removed so it doesn't revisit the left side.

package main
import &quot;fmt&quot;
import &quot;golang.org/x/tour/tree&quot;
func Pop(stack []*tree.Tree) (*tree.Tree, []*tree.Tree) {
last := len(stack) - 1
node := stack[last]
stack[last] = nil
return node, stack[:last]
}
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
defer close(ch)
stack := []*tree.Tree{t}
var node *tree.Tree
for len(stack) &gt; 0 {
node, stack = Pop(stack)
if node.Left != nil {
stack = append(stack, &amp;tree.Tree{nil, node.Value, node.Right}, node.Left)
continue
}
ch &lt;- node.Value
if node.Right != nil {
stack = append(stack, node.Right)
}
}
}
// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
ch1, ch2 := make(chan int), make(chan int)
go Walk(t1, ch1)
go Walk(t2, ch2)
for {
v1, ok1 := &lt;-ch1
v2, ok2 := &lt;-ch2
if v1 != v2 {
return false
}
if !ok1 || !ok2 {
return ok1 == ok2
}
}
}
func PrintTree(t *tree.Tree) {
ch := make(chan int)
go Walk(t, ch)
for i := range ch {
fmt.Printf(&quot;%d &quot;, i)
}
fmt.Println()
}
func main() {
PrintTree(tree.New(1))
PrintTree(&amp;tree.Tree{Value: 1, Right: &amp;tree.Tree{Value: 2}})
fmt.Println(&quot;1 and 2 same (false): &quot;, Same(tree.New(1), tree.New(2)))
fmt.Println(&quot;1 and 1 same (true): &quot;, Same(tree.New(1), tree.New(1)))
fmt.Println(&quot;empty same (true): &quot;, Same(&amp;tree.Tree{}, &amp;tree.Tree{}))
fmt.Println(&quot;diff length same (false): &quot;, Same(&amp;tree.Tree{Value: 1}, &amp;tree.Tree{Value: 2, Left: &amp;tree.Tree{Value: 2}}))
}

The output is:

1 2 3 4 5 6 7 8 9 10 
1 2 
1 and 2 same (false):  false
1 and 1 same (true):  true
empty same (true):  true
diff length same (false):  false

答案14

得分: 1

这可以使用迭代方法解决(这将节省内存)。使用基于此示例的迭代方法:

英文:

This can be solved using an iterative approach (which will save on memory). Using an iterative approach based on this example:

// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
	stack := make([]*tree.Tree, 0)
	for {
		if t != nil {
			stack = append(stack, t)
			t = t.Left
		} else if(len(stack) &gt; 0) {
			lastIndex := len(stack) - 1
			t = stack[lastIndex]
			stack = stack[:lastIndex]
			
			ch &lt;- t.Value
			
			t = t.Right
		} else {
			close(ch)
			return
		}
	}
}

答案15

得分: 0

你应该避免让打开的通道无人看管,否则线程可能会一直等待而永远不会结束。

<!-- language: golang -->

package main
import "code.google.com/p/go-tour/tree"
import "fmt"
func WalkRecurse(t *tree.Tree, ch chan int) {
if t == nil {
return
}
WalkRecurse(t.Left, ch)
ch <- t.Value
WalkRecurse(t.Right, ch)
}
// Walk遍历树t,将所有值发送到通道ch。
func Walk(t *tree.Tree, ch chan int) {
WalkRecurse(t, ch)
close(ch)
}
// Same确定树t1和t2是否包含相同的值。
func Same(t1, t2 *tree.Tree) bool {
var ch1, ch2 chan int = make(chan int), make(chan int)
go Walk(t1, ch1)
go Walk(t2, ch2)
ret := true
for {
v1, ok1 := <- ch1
v2, ok2 := <- ch2
if ok1 != ok2 {
ret = false
}
if ok1 && (v1 != v2) {
ret = false
}
if !ok1 && !ok2 {
break
}
}
return ret
}
func main() {
ch := make(chan int)
go Walk(tree.New(1), ch)
for v := range ch {
fmt.Print(v, " ")
}
fmt.Println()
fmt.Println(Same(tree.New(1), tree.New(1)))
fmt.Println(Same(tree.New(1), tree.New(2)))
}
英文:

You should avoid to let opened channels unattended or a thread can be waiting forever and never ending.

<!-- language: golang -->

package main
import &quot;code.google.com/p/go-tour/tree&quot;
import &quot;fmt&quot;
func WalkRecurse(t *tree.Tree, ch chan int) {
if t == nil {
return
}
WalkRecurse(t.Left, ch)
ch &lt;- t.Value
WalkRecurse(t.Right, ch)
}
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
WalkRecurse(t, ch)
close(ch)
}
// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
var ch1, ch2 chan int = make(chan int), make(chan int)
go Walk(t1, ch1)
go Walk(t2, ch2)
ret := true
for {
v1, ok1 := &lt;- ch1
v2, ok2 := &lt;- ch2
if ok1 != ok2 {
ret = false
}
if ok1 &amp;&amp; (v1 != v2) {
ret = false
}
if !ok1 &amp;&amp; !ok2 {
break
}
}
return ret
}
func main() {
ch := make(chan int)
go Walk(tree.New(1), ch)
for v := range ch {
fmt.Print(v, &quot; &quot;)
}
fmt.Println()
fmt.Println(Same(tree.New(1), tree.New(1)))
fmt.Println(Same(tree.New(1), tree.New(2)))
}

答案16

得分: 0

包主

包主
导入 (
"fmt"
"golang.org/x/tour/tree"
)
// WalkRec遍历树t将所有值发送到通道ch。
func WalkRec(t *tree.Tree, ch chan int) {
if t == nil {
return
}
WalkRec(t.Left, ch)
ch <- t.Value
WalkRec(t.Right, ch)
}
func Walk(t *tree.Tree, ch chan int) {
WalkRec(t, ch)
close(ch)
}
// Same确定树t1和t2是否包含相同的值。
func Same(t1, t2 *tree.Tree) bool {
ch1 := make(chan int)
ch2 := make(chan int)
go Walk(t1, ch1)
go Walk(t2, ch2)
for {
x, okx := <-ch1
y, oky := <-ch2
switch {
case okx != oky:
return false
case x != y:
return false
case okx == oky && okx == false:
return true
}
}
}
func main() {
ch := make(chan int)
go Walk(tree.New(1), ch)
fmt.Println(Same(tree.New(1), tree.New(1)))
fmt.Println(Same(tree.New(2), tree.New(1)))
fmt.Println(Same(tree.New(1), tree.New(2)))
}
英文:

My version

package main
import (
&quot;fmt&quot;
&quot;golang.org/x/tour/tree&quot;
)
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func WalkRec(t *tree.Tree, ch chan int) {
if t == nil {
return
}
WalkRec(t.Left, ch)
ch &lt;- t.Value
WalkRec(t.Right, ch)
}
func Walk(t *tree.Tree, ch chan int) {
WalkRec(t, ch)
close(ch)
}
// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
ch1 := make(chan int)
ch2 := make(chan int)
go Walk(t1, ch1)
go Walk(t2, ch2)
for {
x, okx := &lt;-ch1
y, oky := &lt;-ch2
switch {
case okx != oky:
return false
case x != y:
return false
case okx == oky &amp;&amp; okx == false:
return true
}
}
}
func main() {
ch := make(chan int)
go Walk(tree.New(1), ch)
fmt.Println(Same(tree.New(1), tree.New(1)))
fmt.Println(Same(tree.New(2), tree.New(1)))
fmt.Println(Same(tree.New(1), tree.New(2)))
}

答案17

得分: 0

我写了两个版本,总是读取两个通道的末尾:

package main
import (
"fmt"
"golang.org/x/tour/tree"
)
func Walk(t *tree.Tree, ch chan int) {
var walker func(t *tree.Tree)
walker = func(t *tree.Tree) {
if t == nil {
return
}
walker(t.Left)
ch <- t.Value
walker(t.Right)
}
walker(t)
close(ch)
}
func Same(t1, t2 *tree.Tree, sameChan func(ch1, ch2 chan int) bool) bool {
ch1, ch2 := make(chan int), make(chan int)
go Walk(t1, ch1)
go Walk(t2, ch2)
return sameChan(ch1, ch2)
}
func sameChan1(ch1, ch2 chan int) bool {
areSame := true
for {
v1, ok1 := <-ch1
v2, ok2 := <-ch2
if !ok1 && !ok2 {
return areSame
}
if !ok1 || !ok2 || v1 != v2 {
areSame = false
}
}
}
func sameChan2(ch1, ch2 chan int) bool {
areSame := true
for v1 := range ch1 {
v2, ok2 := <-ch2
if !ok2 || v1 != v2 {
areSame = false
}
}
for _ = range ch2 {
areSame = false
}
return areSame
}
func main() {
fmt.Println(Same(tree.New(1), tree.New(1), sameChan1))
fmt.Println(Same(tree.New(2), tree.New(1), sameChan1))
fmt.Println(Same(tree.New(1), tree.New(2), sameChan1))
fmt.Println(Same(tree.New(1), tree.New(1), sameChan2))
fmt.Println(Same(tree.New(2), tree.New(1), sameChan2))
fmt.Println(Same(tree.New(1), tree.New(2), sameChan2))
}
英文:

I wrote 2 versions that always read both channels to the end:

package main
import (
&quot;fmt&quot;
&quot;golang.org/x/tour/tree&quot;
)
func Walk(t *tree.Tree, ch chan int) {
var walker func(t *tree.Tree)
walker = func(t *tree.Tree) {
if t == nil {
return
}
walker(t.Left)
ch &lt;- t.Value
walker(t.Right)
}
walker(t)
close(ch)
}
func Same(t1, t2 *tree.Tree, sameChan func(ch1, ch2 chan int) bool) bool {
ch1, ch2 := make(chan int), make(chan int)
go Walk(t1, ch1)
go Walk(t2, ch2)
return sameChan(ch1, ch2)
}
func sameChan1(ch1, ch2 chan int) bool {
areSame := true
for {
v1, ok1 := &lt;-ch1
v2, ok2 := &lt;-ch2
if !ok1 &amp;&amp; !ok2 {
return areSame
}
if !ok1 || !ok2 || v1 != v2 {
areSame = false
}
}
}
func sameChan2(ch1, ch2 chan int) bool {
areSame := true
for v1 := range ch1 {
v2, ok2 := &lt;-ch2
if !ok2 || v1 != v2 {
areSame = false
}
}
for _ = range ch2 {
areSame = false
}
return areSame
}
func main() {
fmt.Println(Same(tree.New(1), tree.New(1), sameChan1))
fmt.Println(Same(tree.New(2), tree.New(1), sameChan1))
fmt.Println(Same(tree.New(1), tree.New(2), sameChan1))
fmt.Println(Same(tree.New(1), tree.New(1), sameChan2))
fmt.Println(Same(tree.New(2), tree.New(1), sameChan2))
fmt.Println(Same(tree.New(1), tree.New(2), sameChan2))
}

答案18

得分: 0

这是我使用中序遍历的方法来完成的

package main
import (
"fmt"
"golang.org/x/tour/tree"
)
// Walk函数遍历树t,并将所有的值发送到通道ch中
func Walk(t *tree.Tree, ch chan int) {
if t != nil {
Walk(t.Left, ch)
ch <- t.Value
Walk(t.Right, ch)
}
}
// Same函数判断树t1和t2是否包含相同的值
func Same(t1, t2 *tree.Tree) bool {
c1, c2 := make(chan int), make(chan int)
go Walk(t1, c1)
go Walk(t2, c2)
if <-c1 == <-c2 {
return true
} else {
return false
}
}
func main() {
t1 := tree.New(1)
t2 := tree.New(8)
fmt.Println("这两棵树相同吗?", Same(t1, t2))
}
英文:

That's how I did it using Inorder Traversal

package main
import (
&quot;fmt&quot;
&quot;golang.org/x/tour/tree&quot;
)
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
if t != nil {
Walk(t.Left, ch)
ch &lt;- t.Value
Walk(t.Right, ch)
}
}
// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
c1, c2 := make(chan int), make(chan int)
go Walk(t1, c1)
go Walk(t2, c2)
if &lt;-c1 == &lt;-c2 {
return true
} else {
return false
}
}
func main() {
t1 := tree.New(1)
t2 := tree.New(8)
fmt.Println(&quot;the two trees are same?&quot;, Same(t1, t2))
}

答案19

得分: 0

因为问题只是说树只有10个节点,所以下面是我在阅读其他答案后给出的答案:

func Walk(t *tree.Tree, ch chan int) {
defer close(ch)
var walker func(t *tree.Tree)
walker = func(t *tree.Tree) {
if t == nil {
return
}
walker(t.Left)
ch <- t.Value
walker(t.Right)
}
walker(t)
}
func Same(t1, t2 *tree.Tree) bool {
ch1, ch2 := make(chan int), make(chan int)
go Walk(t1, ch1)
go Walk(t2, ch2)
for range make([]struct{}, 10) {
if <-ch1 != <-ch2 {
return false
}
}
return true
}
英文:

because the question just said the tree just 10 nodes,then following is my answer after read other answers:

func Walk(t *tree.Tree, ch chan int) {
defer close(ch)
var walker func(t *tree.Tree)
walker = func(t *tree.Tree) {
if t == nil {
return
}
walker(t.Left)
ch &lt;- t.Value
walker(t.Right)
}
walker(t)
}
func Same(t1, t2 *tree.Tree) bool {
ch1, ch2 := make(chan int), make(chan int)
go Walk(t1, ch1)
go Walk(t2, ch2)
for range make([]struct{}, 10) {
if &lt;-ch1 != &lt;-ch2 {
return false
}
}
return true
}

答案20

得分: 0

这是一个不依赖于不同树长度的解决方案,也不依赖于遍历顺序:

package main
import (
"fmt"
"golang.org/x/tour/tree"
)
// Walk函数遍历树t并将所有值发送到通道ch。
func Walk(t *tree.Tree, ch chan int) {
var walk func(*tree.Tree)
walk = func(tr *tree.Tree) {
if tr == nil {
return
}
walk(tr.Left)
ch <- tr.Value
walk(tr.Right)
}
walk(t)
close(ch)
}
// merge函数将通道ch中的值合并到映射m中。
func merge(ch chan int, m map[int]int) {
for i := range ch {
count, ok := m[i]
if ok {
m[i] = count + 1
} else {
m[i] = 1
}
}
}
// Same函数确定树t1和t2是否包含相同的值。
func Same(t1, t2 *tree.Tree) bool {
ch1 := make(chan int, 100)
ch2 := make(chan int, 100)
m := make(map[int]int)
go Walk(t1, ch1)
go Walk(t2, ch2)
merge(ch1, m)
merge(ch2, m)
for _, count := range m {
if count != 2 {
return false
}
}
return true
}
英文:

Here's a solution that doesn't depend on differing tree lengths, neither does it depend on traversal order:

package main
import (
&quot;fmt&quot;
&quot;golang.org/x/tour/tree&quot;
)
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
var walk func(*tree.Tree)
walk = func(tr *tree.Tree) {
if tr == nil {
return
}
walk(tr.Left)
ch &lt;- tr.Value
walk(tr.Right)
}
walk(t)
close(ch)
}
func merge(ch chan int, m map[int]int) {
for i := range ch {
count, ok := m[i]
if ok {
m[i] = count + 1
} else {
m[i] = 1
}
}
}
// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
ch1 := make(chan int, 100)
ch2 := make(chan int, 100)
m := make(map[int]int)
go Walk(t1, ch1)
go Walk(t2, ch2)
merge(ch1, m)
merge(ch2, m)
for _, count := range m {
if count != 2 {
return false
}
}
return true
}

答案21

得分: 0

对于对此感兴趣的人,如果你想知道如何在不创建单独的递归函数的情况下解决这个问题,这里有一个使用堆栈的答案:

func Walk(t *tree.Tree, ch chan int) {
	defer close(ch)
	visitStack := []*tree.Tree{t}
	visited := make(map[*tree.Tree]bool, 1)
	for len(visitStack) > 0 {
		var n *tree.Tree
		n, visitStack = visitStack[len(visitStack)-1], visitStack[:len(visitStack)-1]
		if visited[n] {
			ch <- n.Value
			continue
		}
		if n.Right != nil {
			visitStack = append(visitStack, n.Right)
		}
		visitStack = append(visitStack, n)
		if n.Left != nil {
			visitStack = append(visitStack, n.Left)
		}
		visited[n] = true
	}
}
英文:

For whoever interested, if you wonder how to solve this without creating a separate recursive function, here is an answer using a stack:

func Walk(t *tree.Tree, ch chan int) {
defer close(ch)
visitStack := []*tree.Tree{t}
visited := make(map[*tree.Tree]bool, 1)
for len(visitStack) &gt; 0 {
var n *tree.Tree
n, visitStack = visitStack[len(visitStack)-1], visitStack[:len(visitStack)-1]
if visited[n] {
ch &lt;- n.Value
continue
}
if n.Right != nil {
visitStack = append(visitStack, n.Right)
}
visitStack = append(visitStack, n)
if n.Left != nil {
visitStack = append(visitStack, n.Left)
}
visited[n] = true
}
}

答案22

得分: 0

package main

import "golang.org/x/tour/tree"
import "fmt"

// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
if t == nil {
return
}
Walk(t.Left, ch)
ch <- t.Value
Walk(t.Right, ch)
}

func WalkATree(t *tree.Tree, ch chan int) {
Walk(t, ch)
close(ch)
}

// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
ch1 := make(chan int)
ch2 := make(chan int)
go WalkATree(t1, ch1)
go WalkATree(t2, ch2)
var v1, v2 int
var ok1, ok2 bool
for {
v1, ok1 = <-ch1
v2, ok2 = <-ch2
if !ok1 && !ok2 {
return true
}
if !ok1 && ok2 || ok1 && !ok2 {
return false
}
if v1 != v2 {
return false
}
}
}

func main() {
fmt.Println(Same(tree.New(1), tree.New(1)))
}

英文:

A clear answer:

package main
import &quot;golang.org/x/tour/tree&quot;
import &quot;fmt&quot;
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
if t == nil {
return
}
Walk(t.Left, ch)
ch &lt;- t.Value
Walk(t.Right, ch)
}
func WalkATree(t *tree.Tree, ch chan int) {
Walk(t, ch)
close(ch)
}
// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
ch1 := make(chan int)
ch2 := make(chan int)
go WalkATree(t1, ch1)
go WalkATree(t2, ch2)
var v1, v2 int
var ok1, ok2 bool
for {
v1, ok1 = &lt;- ch1
v2, ok2 = &lt;- ch2
if !ok1 &amp;&amp; !ok2 {
return true
}
if !ok1 &amp;&amp; ok2 || ok1 &amp;&amp; !ok2 {
return false
}
if v1 != v2 {
return false
}
}
}
func main() {
fmt.Println(Same(tree.New(1), tree.New(1)))
}

答案23

得分: 0

这是我的解决方案,没有使用defer魔法。我认为这样会更容易阅读,所以值得分享 Go Tour练习#7:二叉树的等价性

奖励: 这个版本实际上解决了教程练习中的问题,并给出了正确的结果。

package main

import (
	"golang.org/x/tour/tree"
	"fmt"
)

// Walk遍历树t,将树中的所有值发送到通道ch。
func Walk(t *tree.Tree, ch chan int) {
	walkRecursive(t, ch)
	close(ch)
}

func walkRecursive(t *tree.Tree, ch chan int) {
	if t != nil {
		walkRecursive(t.Left, ch)
		ch <- t.Value
		walkRecursive(t.Right, ch)
	}
}

// Same确定树t1和t2是否包含相同的值。
func Same(t1, t2 *tree.Tree) bool {
	var br bool
	ch1, ch2 := make(chan int), make(chan int)
	go Walk(t1, ch1)
	go Walk(t2, ch2)

	for i:= range ch1 {
		if i == <-ch2 {
			br = true
		} else {
			br = false
			break
		}
	}
	return br
}

func main() {
	ch := make(chan int)
	go Walk(tree.New(1), ch)
	
	for i := range ch {
		fmt.Println(i)
	}
	
	fmt.Println(Same(tree.New(1), tree.New(2)))
    fmt.Println(Same(tree.New(1), tree.New(1)))
    fmt.Println(Same(tree.New(2), tree.New(1)))
}

因此,输出如下:

1
2
3
4
5
6
7
8
9
10
false
true
false
英文:

Here's my solution, without the defer magic. I thought this would be a bit easier to read, so it would worth sharing Go Tour练习#7:二叉树的等价性

Bonus: This version actually solves the problem in the tour's exercise and gives proper results.

package main
import (
&quot;golang.org/x/tour/tree&quot;
&quot;fmt&quot;
)
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
walkRecursive(t, ch)
close(ch)
}
func walkRecursive(t *tree.Tree, ch chan int) {
if t != nil {
walkRecursive(t.Left, ch)
ch &lt;- t.Value
walkRecursive(t.Right, ch)
}
}
// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
var br bool
ch1, ch2 := make(chan int), make(chan int)
go Walk(t1, ch1)
go Walk(t2, ch2)
for i:= range ch1 {
if i == &lt;-ch2 {
br = true
} else {
br = false
break
}
}
return br
}
func main() {
ch := make(chan int)
go Walk(tree.New(1), ch)
for i := range ch {
fmt.Println(i)
}
fmt.Println(Same(tree.New(1), tree.New(2)))
fmt.Println(Same(tree.New(1), tree.New(1)))
fmt.Println(Same(tree.New(2), tree.New(1)))
}

So the output is as follows:

1
2
3
4
5
6
7
8
9
10
false
true
false

答案24

得分: 0

package main

import (
	"fmt"
	"golang.org/x/tour/tree"
)

// Walk函数遍历树t,并将所有值发送到通道ch。
func Walk(t *tree.Tree, ch chan int) {
	walkRecursive(t, ch)
	close(ch)
}

func walkRecursive(t *tree.Tree, ch chan int) {
	if t == nil {
		return
	}
	walkRecursive(t.Left, ch)
	ch <- t.Value
	walkRecursive(t.Right, ch)
}

// Same函数确定树t1和t2是否包含相同的值。
func Same(t1, t2 *tree.Tree) bool {
	ch1 := make(chan int)
	ch2 := make(chan int)
	go Walk(t1, ch1)
	go Walk(t2, ch2)

	for {
		v1, ok1 := <-ch1
		v2, ok2 := <-ch2
		if ok1 != ok2 {
			return false
		}
		if !ok1 {
			return true
		}
		if v1 != v2 {
			return false
		}
	}
}

func main() {
	fmt.Println(Same(tree.New(1), tree.New(2)))
}
英文:
package main

import (
	&quot;fmt&quot;
	&quot;golang.org/x/tour/tree&quot;
)

// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
	walkRecursive(t, ch)
	close(ch)
}

func walkRecursive(t *tree.Tree, ch chan int) {
	if t == nil {
		return
	}
	walkRecursive(t.Left, ch)
	ch &lt;- t.Value
	walkRecursive(t.Right, ch)
}

// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
	ch1 := make(chan int)
	ch2 := make(chan int)
	go Walk(t1, ch1)
	go Walk(t2, ch2)

	for {
		v1, ok1 := &lt;-ch1
		v2, ok2 := &lt;-ch2
		if ok1 != ok2 {
			return false
		}
		if !ok1 {
			return true
		}
		if v1 != v2 {
			return false
		}
	}
}

func main() {
	fmt.Println(Same(tree.New(1), tree.New(2)))
}

答案25

得分: 0

Haven't seen it so far in this thread. I used the nil channel technique presented in just for func

The issue with closing the channels was solved by kicking them off in an goroutine iife.

I think I could check more performant for equality though.

package main

import (
	"fmt"
	"reflect"
	"sort"

	"golang.org/x/tour/tree"
)

// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
	ch <- t.Value
	if t.Right != nil {
		Walk(t.Right, ch)
	}
	if t.Left != nil {
		Walk(t.Left, ch)
	}

}

// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {

	c1 := make(chan int)
	s1 := []int{}

	go func() {
		Walk(t1, c1)
		close(c1)
	}()

	c2 := make(chan int)
	s2 := []int{}

	go func() {
		Walk(t2, c2)
		close(c2)
	}()

	for c1 != nil || c2 != nil {
		select {
		case v, ok := <-c1:
			if !ok {
				c1 = nil
				sort.Ints(s1)
				continue
			}
			s1 = append(s1, v)
		case v, ok := <-c2:
			if !ok {
				c2 = nil
				sort.Ints(s2)
				continue
			}
			s2 = append(s2, v)
		}
	}
	return reflect.DeepEqual(s1, s2)
}

func main() {
	fmt.Println(Same(tree.New(1), tree.New(1)))
}
英文:

Haven't seen it so far in this thread. I used the nil channel technique presented in just for func

The issue with closing the channels was solved by kicking them off in an goroutine iife.

I think I could check more performant for equality though.

package main

import (
	&quot;fmt&quot;
	&quot;reflect&quot;
	&quot;sort&quot;

	&quot;golang.org/x/tour/tree&quot;
)

// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
	ch &lt;- t.Value
	if t.Right != nil {
		Walk(t.Right, ch)
	}
	if t.Left != nil {
		Walk(t.Left, ch)
	}

}

// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {

	c1 := make(chan int)
	s1 := []int{}

	go func() {
		Walk(t1, c1)
		close(c1)
	}()

	c2 := make(chan int)
	s2 := []int{}

	go func() {
		Walk(t2, c2)
		close(c2)
	}()

	for c1 != nil || c2 != nil {
		select {
		case v, ok := &lt;-c1:
			if !ok {
				c1 = nil
				sort.Ints(s1)
				continue
			}
			s1 = append(s1, v)
		case v, ok := &lt;-c2:
			if !ok {
				c2 = nil
				sort.Ints(s2)
				continue
			}
			s2 = append(s2, v)
		}
	}
	return reflect.DeepEqual(s1, s2)
}

func main() {
	fmt.Println(Same(tree.New(1), tree.New(1)))
}

答案26

得分: 0

如果一个人在他的Walk逻辑中使用递归调用,并且希望向通道消费者发出没有更多项的信号,似乎可以将大部分Walk逻辑放入第二个函数中,调用该第二个函数,等待其完成,然后关闭通道。

在下面的示例中,第二个("内部Walk")函数是直接在Walk函数内部的一个"闭包",但它不必是。

package main
import "golang.org/x/tour/tree"
import "fmt"
// Walk遍历树t,将树中的所有值发送到通道ch。
func Walk(t *tree.Tree, ch chan int) {
defer close(ch)
var iw func(*tree.Tree)
iw = func(it *tree.Tree) {
if it == nil {
return
}
iw(it.Left)
ch <- it.Value
iw(it.Right)
}
iw(t)
}
// Same确定树t1和t2是否包含相同的值。
func Same(t1, t2 *tree.Tree) bool {
ch1 := make(chan int)
ch2 := make(chan int)
go Walk(t1, ch1)
go Walk(t2, ch2)
for {
v1, more1 := <- ch1
v2, more2 := <- ch2
if (!more1 && !more2) {
return true
}
if more1 != more2 || v1 != v2 {
return false
}
}
}
func main() {
fmt.Println(Same(tree.New(1), tree.New(1)))
fmt.Println(Same(tree.New(1), tree.New(2)))
}
英文:

If one is using recursive calls with one's Walk logic and one wishes to signal channel-consumers that there are no more items, it seems that one can put the majority of one's Walk logic into a second function, invoke that second function, wait for it to complete, then close the channel.

In the example below, the second ("inner Walk") function is a "closure" directly inside the Walk function, but it needn't be.

package main
import &quot;golang.org/x/tour/tree&quot;
import &quot;fmt&quot;
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
defer close(ch)
var iw func(*tree.Tree)
iw = func(it *tree.Tree) {
if it == nil {
return
}
iw(it.Left)
ch &lt;- it.Value
iw(it.Right)
}
iw(t)
}
// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
ch1 := make(chan int)
ch2 := make(chan int)
go Walk(t1, ch1)
go Walk(t2, ch2)
for {
v1, more1 := &lt;- ch1
v2, more2 := &lt;- ch2
if (!more1 &amp;&amp; !more2) {
return true
}
if more1 != more2 || v1 != v2 {
return false
}
}
}
func main() {
fmt.Println(Same(tree.New(1), tree.New(1)))
fmt.Println(Same(tree.New(1), tree.New(2)))
}

答案27

得分: 0

如何只稍微改变传入参数的数量呢?

package main

import (
	"fmt"
	"golang.org/x/tour/tree"
)

// Walk遍历树t,将树中的所有值发送到通道ch。
func Walk(t *tree.Tree, ch chan int, recursion bool) {
	if t != nil {
		ch <- t.Value
		Walk(t.Left, ch, true)
		Walk(t.Right, ch, true)
	}
	
	if !recursion {
		close(ch)
	}
}

// Same确定树t1和t2是否包含相同的值。
func Same(t1, t2 *tree.Tree) bool {
	t1_map := map[int]int{}
	t2_map := map[int]int{}
	t1_ch := make(chan int)
	t2_ch := make(chan int)
	
	go Walk(t1, t1_ch, false)
	go Walk(t2, t2_ch, false)
	
	for value := range t1_ch {
		t1_map[value]++
	}
	
	for value := range t2_ch {
		t2_map[value]++
	}
	
	if len(t1_map) != len(t2_map) {
		return false
	}
	
	for t1_key, t1_value := range t1_map {
		t2_value, t2_exists := t2_map[t1_key]
		
		if (!t2_exists) || (t1_value != t2_value) {
			return false
		}
	}
	
	return true
}

func main() {
	t1 := tree.New(1)
	t2 := tree.New(2)
	t3 := tree.New(1)
	
	fmt.Println(Same(t1, t2))
	fmt.Println(Same(t1, t3))
	fmt.Println(Same(t3, t2))
}
英文:

How about just change count of incoming arguments by a little?

package main

import (
	&quot;fmt&quot;
	&quot;golang.org/x/tour/tree&quot;
)

// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int, recursion bool) {
	if t != nil {
		ch &lt;- t.Value
		Walk(t.Left, ch, true)
		Walk(t.Right, ch, true)
	}
	
	if !recursion {
		close(ch)
	}
}

// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
	t1_map := map[int]int{}
	t2_map := map[int]int{}
	t1_ch := make(chan int)
	t2_ch := make(chan int)
	
	go Walk(t1, t1_ch, false)
	go Walk(t2, t2_ch, false)
	
	for value := range t1_ch {
		t1_map[value]++
	}
	
	for value := range t2_ch {
		t2_map[value]++
	}
	
	if len(t1_map) != len(t2_map) {
		return false
	}
	
	for t1_key, t1_value := range t1_map {
		t2_value, t2_exists := t2_map[t1_key]
		
		if (!t2_exists) || (t1_value != t2_value) {
			return false
		}
	}
	
	return true
}

func main() {
	t1 := tree.New(1)
	t2 := tree.New(2)
	t3 := tree.New(1)
	
	fmt.Println(Same(t1, t2))
	fmt.Println(Same(t1, t3))
	fmt.Println(Same(t3, t2))
}

答案28

得分: 0

在作者的情况下,他们应该只需更改Same函数以避免无限循环:

func Same(t1, t2 *tree.Tree) bool {
	ch1 := make(chan int)
    ch2 := make(chan int)

    go Walk(t1, ch1)
    go Walk(t2, ch2)

	if <-ch1 != <-ch2 {
		return false
	}

    return true
}
英文:

In the author's case, they should just change the Same function to avoid an infinite loop:

func Same(t1, t2 *tree.Tree) bool {
	ch1 := make(chan int)
    ch2 := make(chan int)

    go Walk(t1, ch1)
    go Walk(t2, ch2)

	if &lt;-ch1 != &lt;-ch2 {
		return false
	}

    return true
}

答案29

得分: 0

添加我的解决方案供他人参考。由于与其他一些在这里进行了详细描述的解决方案非常相似,所以没有添加太多解释。希望它能有所帮助。无论如何,能够比较我们对这些练习的不同方法是非常好的!

此外,您可以在Go playground中尝试这段代码。

func Walk(t *tree.Tree, ch chan int) {
defer close(ch)
var walkinto func(t *tree.Tree)
walkinto = func(t *tree.Tree) {
if t == nil {
return
}
walkinto(t.Left)
ch <- t.Value
walkinto(t.Right)
}
walkinto(t)
}
func Same(t1, t2 *tree.Tree) bool {
ch1 := make(chan int)
ch2 := make(chan int)
go Walk(t1, ch1)
go Walk(t2, ch2)
for i := range ch1 {
if i != <-ch2 {
return false
}
}
return true
}
func main() {
fmt.Printf("Positive result. Expecting true: %v\n", Same(tree.New(1), tree.New(1)))
fmt.Printf("Negative result. Expecting false: %v\n", Same(tree.New(1), tree.New(2)))
}
英文:

Adding my solution for others to reference. Not adding a lot of explanations as it is pretty similar to several others well described here. Hope it helps though.
In any case, being able to compare our different approaches to these exercises is just great!

Also, you can try it code in Go playground

func Walk(t *tree.Tree, ch chan int) {
defer close(ch)
var walkinto func(t *tree.Tree)
walkinto = func(t *tree.Tree) {
if t == nil {
return
}
walkinto(t.Left)
ch &lt;- t.Value
walkinto(t.Right)
}
walkinto(t)
}
func Same(t1, t2 *tree.Tree) bool {
ch1 := make(chan int)
ch2 := make(chan int)
go Walk(t1, ch1)
go Walk(t2, ch2)
for i := range ch1 {
if i != &lt;-ch2 {
return false
}
}
return true
}
func main() {
fmt.Printf(&quot;Positive result. Expecting true: %v\n&quot;, Same(tree.New(1), tree.New(1)))
fmt.Printf(&quot;Negative result. Expecting false: %v\n&quot;, Same(tree.New(1), tree.New(2)))
}

答案30

得分: 0

See demo on the Go Playground: https://go.dev/play/p/MrsAWvkavlL

package main
import (
"fmt"
"golang.org/x/tour/tree"
)
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
if t == nil {
return
}
// inorder traversal
Walk(t.Left, ch)
ch <- t.Value // This let's us pass the value to the channel at the right time
Walk(t.Right, ch)
}
// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
ch1 := make(chan int)
ch2 := make(chan int)
go func() {
Walk(t1, ch1)
close(ch1) // Need to close channel to prevent deadlock
}()
go func() {
Walk(t2, ch2)
close(ch2) // Need to close channel to prevent deadlock
}()
// since values come inorder we can block and check each value
if <-ch1 != <-ch2 {
return false
}
return true
}
func main() {
fmt.Println(Same(tree.New(1), tree.New(1)))
fmt.Println(Same(tree.New(1), tree.New(2)))
}
英文:

See demo on the Go Playground: https://go.dev/play/p/MrsAWvkavlL

package main
import (
&quot;fmt&quot;
&quot;golang.org/x/tour/tree&quot;
)
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
if t == nil {
return
}
// inorder traversal
Walk(t.Left, ch)
ch &lt;- t.Value // This let&#39;s us pass the value to the channel at the right time
Walk(t.Right, ch)
}
// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
ch1 := make(chan int)
ch2 := make(chan int)
go func() {
Walk(t1, ch1)
close(ch1) // Need to close channel to prevent deadlock
}()
go func() {
Walk(t2, ch2)
close(ch2) // Need to close channel to prevent deadlock
}()
// since values come inorder we can block and check each value
if &lt;- ch1 != &lt;-ch2 {
return false
}
return true
}
func main() {
fmt.Println(Same(tree.New(1), tree.New(1)))
fmt.Println(Same(tree.New(1), tree.New(2)))
}

huangapple
  • 本文由 发表于 2012年9月1日 08:51:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/12224042.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定