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
My version
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)))
}
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 valuesk, 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 (
"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)))
}
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.
Here's the full solution using ideas here and from the Google Group thread
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)))
}
That's how I did it using 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))
}
This is my solution.
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 := 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 == 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)))
}
Here's my solution, without the defer
magic. I thought this would be a bit easier to read, so it would worth sharing :)
Bonus: This version actually solves the problem in the tour's exercise and gives proper results.
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)))
}
So the output is as follows:
1
2
3
4
5
6
7
8
9
10
false
true
false