67

我正在尝试在 go tour 中解决等效的二叉树练习。这就是我所做的;

package main

import "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.Left != nil {
        Walk(t.Left, ch)
    }
    ch <- 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 := <-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)))
}

但是,如果树中没有更多元素,我不知道如何发出信号。我不能使用close(ch)onWalk()因为它会在发送所有值之前关闭通道(因为递归。)有人可以帮我吗?

4

29 回答 29

125

golang-nuts 组中提出了一个使用闭包的优雅解决方案,

func Walk(t *tree.Tree, ch chan int) {
    defer close(ch) // <- 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 <- t.Value
        walk(t.Right)
    }
    walk(t)
}
于 2012-09-01T03:18:16.490 回答
32

如果您的 Walk 函数不会自行递归,您可以使用 close() 。即步行会做:

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

walkRecurse 或多或少是您当前的 Walk 函数,但在 walkRecurse 上递归。(或者您将 Walk 重写为迭代 - 这当然更麻烦)使用这种方法,您的 Same() 函数必须了解通道已关闭,这是通过表单的通道接收完成的

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

ok1当和ok2不同时采取适当的行动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 中的节点数

于 2012-09-01T01:07:57.013 回答
32

这是使用此处和Google Group线程中的想法的完整解决方案

package main

import "fmt"
import "code.google.com/p/go-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) {
    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 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 := <- 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)))

}
于 2014-07-04T19:43:50.100 回答
16

我就是这样做的,不同之处在于您可以将其包装Walk到匿名函数defer close(ch)中。因此您不必定义其他命名的递归函数

package main

import (
    "golang.org/x/tour/tree"
    "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)
}
// 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 := <- 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)))
}
于 2016-11-10T18:15:26.680 回答
6

虽然我的第一个直觉是也包含递归遍历并关闭通道,但我觉得这不符合练习的精神。

练习文本包含以下信息:

该函数tree.New(k)构造一个随机结构(但始终排序)的二叉树,其中包含 values 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 更容易。

于 2018-03-15T11:59:02.790 回答
5

这是我想出的解决方案:

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

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

func Same(t1, t2 *tree.Tree) bool{
    ch:=make(chan int)
    dh:=make(chan int)
    go Walk(t1,ch)
    go Walk(t2,dh)

    for i:=range ch {
        j,ok:=<-dh
        if(i!=j||!ok)  {return false} 
    }

    return true
}
于 2014-11-21T08:06:20.677 回答
5

这是我的解决方案。

package main

import (
  "golang.org/x/tour/tree"
  "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)
}

// 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 := <- 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))) 
}

于 2020-08-22T03:50:36.387 回答
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; 
}
于 2013-06-19T18:45:02.760 回答
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
}
于 2013-07-27T09:42:17.077 回答
3
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 {
        Walk(t.Left, ch)
        ch <- 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 != <-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)))
}
于 2020-04-08T20:39:53.617 回答
3

使用带有匿名函数的 goroutine

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

这是易于阅读的代码

行走功能

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 {
            // both closed at the same time (and all values until now were equal)
            return true
        }
    
        if !ok1 || !ok2 || v1 != v2 {
            return false
        }
    }
    return true
}

主要功能

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
}
于 2021-11-23T17:27:10.760 回答
2

试图使用地图结构解决这个问题。

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
}
于 2018-02-05T22:15:12.620 回答
2

以前的所有答案都没有解决有关Same功能的任务。问题是:

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

它不应该考虑树的结构。这就是为什么以下测试失败的原因,在这两行中都给了我们错误:

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

因此,要解决任务,您需要缓冲一棵树的所有结果,并检查第二棵树的值是否在第一棵树中。

这是我的解决方案,它并不理想:):

// 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
}
于 2018-03-28T13:56:08.753 回答
0

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

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 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 := <- 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)))
}
于 2015-01-19T02:05:56.763 回答
0

我的版本

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 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 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 := <-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)))
}
于 2016-03-21T14:26:57.243 回答
0

我写了 2 个版本,总是把两个频道都读到最后:

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))
}
于 2016-05-09T18:31:27.677 回答
0

这就是我使用中序遍历的方式

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 {
        Walk(t.Left, ch)
        ch <- 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 <-c1 == <-c2 {
        return true
    } else {
        return false
    }
}

func main() {
    t1 := tree.New(1)
    t2 := tree.New(8)
    fmt.Println("the two trees are same?", Same(t1, t2))
}
于 2016-06-22T15:30:42.630 回答
0

因为问题刚刚说树只有10个节点,那么以下是我阅读其他答案后的答案:</p>

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
}
于 2016-09-10T02:56:58.317 回答
0

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

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) {
    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)
}

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
}
于 2016-09-23T07:19:11.157 回答
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
    }
}
于 2017-04-03T01:33:15.123 回答
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)))
}
于 2017-10-18T16:08:55.803 回答
0

这是我的解决方案,没有defer魔法。我认为这会更容易阅读,所以值得分享:)

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

package main

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

// 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 <- 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 == <-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
于 2019-12-09T13:48:53.750 回答
0
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) {
    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 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 := <-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)))
}

于 2020-02-11T04:41:03.217 回答
0

到目前为止还没有在这个线程中看到它。我使用了func中介绍的 nil 通道技术

通过在 goroutine iife 中启动它们来解决关闭通道的问题。

我想我可以检查更多的性能是否平等。

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)))
}
于 2020-06-03T19:21:18.130 回答
0

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

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

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) {
    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 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 := <- 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)))
}
于 2021-03-27T08:20:10.213 回答
0

这是一个非递归解决方案(即在大输入上不会出现堆栈空间问题),它也不需要单独的已访问地图 - 它只使用单个堆栈数据结构。避免访问映射的技巧是从堆栈中删除已访问的条目,而是tree.Tree为已访问的条目创建新实例,同时删除左侧,这样它就不会重新访问左侧。

package main

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

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) > 0 {
        node, stack = Pop(stack)
        if node.Left != nil {
            stack = append(stack, &tree.Tree{nil, node.Value, node.Right}, node.Left)
            continue
        }

        ch <- 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 := <-ch1
        v2, ok2 := <-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("%d ", i)
    }
    fmt.Println()
}

func main() {
    PrintTree(tree.New(1))
    PrintTree(&tree.Tree{Value: 1, Right: &tree.Tree{Value: 2}})

    fmt.Println("1 and 2 same (false): ", Same(tree.New(1), tree.New(2)))
    fmt.Println("1 and 1 same (true): ", Same(tree.New(1), tree.New(1)))
    fmt.Println("empty same (true): ", Same(&tree.Tree{}, &tree.Tree{}))
    fmt.Println("diff length same (false): ", Same(&tree.Tree{Value: 1}, &tree.Tree{Value: 2, Left: &tree.Tree{Value: 2}}))
}

输出是:

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
于 2021-06-05T23:42:23.203 回答
0

稍微改变传入参数的数量怎么样?

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, recursion bool) {
    if t != nil {
        ch <- 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))
}
于 2021-09-10T09:07:39.033 回答
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
}
于 2021-10-01T16:30:57.053 回答
0

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

// 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) > 0) {
            lastIndex := len(stack) - 1
            t = stack[lastIndex]
            stack = stack[:lastIndex]
            
            ch <- t.Value
            
            t = t.Right
        } else {
            close(ch)
            return
        }
    }
}
于 2021-10-03T18:59:52.790 回答