I am trying to solve equivalent binary trees exercise on go tour. Here is what I did;
package main
import \"tour/tree\"
import \"fmt\"
// Walk walks the tr
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)))
}
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 hazzle) 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 := <-ch
g, ok2 := <-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 < countT1; i++ {
if <-ch1 != <-ch2 {
return false
}
}
return true
}
You'll have to implement the countTreeNodes() function, which should count the number of nodes in a *Tree
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("Should return true:", Same(tree.New(1), tree.New(1)))
fmt.Println("Should return false:", 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 :) :
// 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
}
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) > 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
}
}
This is my solution. It properly checks for differences in the length of the two sequences.
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;
}