Подтвердить что ты не робот

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) для Walk() потому что он закрывает канал перед отправкой всех значений (из-за рекурсии). Кто-нибудь может мне помочь?

4b9b3361

Ответ 1

Вы можете использовать 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

И примите правильные меры, когда 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

Ответ 2

Элегантное решение с помощью закрытия было представлено в golang орехов группы,

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

Ответ 3

Здесь полное решение, использующее идеи здесь и из Группа Google

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

}

Ответ 4

Вот как я это сделал, разница в том, что вы можете обернуть 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)))
}

Ответ 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
}

Ответ 6

Это мое решение. Он правильно проверяет различия в длине двух последовательностей.

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; 
}

Ответ 7

Вы получили это почти правильно, нет необходимости использовать оператор select, потому что вы слишком часто будете проходить через событие default, здесь мое решение работает без необходимости подсчета количества узлов в 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 := <-ch2
        if more {
            if i != j { return false }
        } else { return false }
    }

    return true
}

Ответ 8

Хотя моей первой интуицией было также завернуть рекурсивную прогулку и закрыть каналы, я чувствовал, что это не в духе упражнения.

Текст упражнения содержит следующую информацию:

Функция 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)))
}

Если бы целью было бегать по деревьям произвольного размера, то лучше всего было бы реагировать на закрытые каналы, но я чувствовал, что это было простое упражнение с намеренно наложенными ограничениями, чтобы облегчить жизнь новому суслику.

Ответ 9

Попытался решить эту проблему, используя структуру карты.

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
}

Ответ 10

Все предыдущие ответы не решают задачу о 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)) должна возвращать true, а Same(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
}

Ответ 11

Вам следует избегать открытия открытых каналов без присмотра или нить может ждать всегда и никогда не заканчиваться.

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

Ответ 12

Моя версия

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

Ответ 13

Я написал 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))
}

Ответ 14

Вот как я это сделал с помощью Inorder Traversal

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

Ответ 15

потому что вопрос просто сказал, что дерево всего 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
}

Ответ 16

Здесь решение, которое не зависит от разной длины дерева и не зависит от порядка обхода:

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
}

Ответ 17

Для тех, кто заинтересован, если вам интересно, как решить эту проблему без создания отдельной рекурсивной функции, вот ответ с использованием стека:

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

Ответ 18

Четкий ответ:

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