题目地址 https://tour.go-zh.org/concur...
前提:对两棵二叉树进行中序遍历,若是得到的数值序列相同,则将其视为等价二叉树。
要求:使用goroutine协程
思想:其实和不使用协程的思路差不多,分别中序遍历两棵树,得到数值序列,比较两个序列是否相等。
若是使用协程,则可以很方便地并发遍历两棵树,再利用信道传输每个节点的数值,边遍历边比较。因为Go协程可利用多CPU核心,若是电脑有两个以上的CPU核心,则实际的运行时间会大大加快。
类似的,在其他编程语言里,可以使用多线程,然后通过队列传送信息给主线程。边遍历边比较。
树的数据结构。文档和源代码地址:https://pkg.go.dev/golang.org...
// A Tree is a binary tree with integer values.
type Tree struct {
Left *Tree
Value int
Right *Tree
}
题目的模板提醒我们,通过Same
函数检测两棵树是否相同,通过Walk
函数遍历树。
思想就是,在Same
函数中分别创建两个信道ch1
,ch2
,启动两个协程运行Walk
函数,两个Walk
函数分别遍历两棵树,分别通过两个信道将遍历的数值传给Same
函数,Same
会同时比对两个Walk
传输过来的数值,若是直到两个Walk
遍历完树(也就是两个Walk
都关闭了信道),Same
的数值比对都没有出错,则可视为两棵树等价。
package main
import "golang.org/x/tour/tree"
// Walk 步进 tree t 将所有的值从 tree 发送到 channel ch。
func Walk(t *tree.Tree, ch chan int)
// Same 检测树 t1 和 t2 是否含有相同的值。
func Same(t1, t2 *tree.Tree) bool
func main() {
}
实际代码
package main
import "fmt"
import "tree"
// Walk 步进 tree t 将所有的值从 tree 发送到 channel ch。
func Walk(t *tree.Tree, ch chan int) {
if t == nil {
return
}
stack := make([]*tree.Tree, 0)
for len(stack) > 0 || t != nil {
for t != nil {
stack = append(stack, t)
t = t.Left
}
node := stack[len(stack)-1]
stack = stack[:len(stack)-1]
ch <- node.Value
t = node.Right
}
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 {
v1, ok1 := <-ch1
v2, ok2 := <-ch2
if ok1 && ok2 {
//两个信道都在开启状态
if v1 != v2 {
return false
}
} else if ok1 || ok2 {
//一个信道已关闭,说明两棵树节点数不同
return false
} else {
//两个信道同时关闭,说明两棵树节点数相同
break
}
}
return true
}
func main() {
fmt.Println(Same(tree.New(1), tree.New(1)))
fmt.Println(Same(tree.New(2), tree.New(1)))
}
在Walk
中,可以创建一个切片"stack
"来模拟栈实现中序遍历。压入栈是stack = append(stack, t)
,弹出栈是node := stack[len(stack)-1]
,stack = stack[:len(stack)-1]
。每遍历一个节点,就将数值传入信道ch
。遍历完成,关闭信道close(ch)
。
在Same
中,创建两个协程同时遍历两棵树,两个信道分别接收两个Walk
传来的数值。两棵树等价的必要条件就是,树的节点数相同,若是有一棵树提前遍完成,则代表这棵树节点数少一些,这两棵树必然不等价。只有两棵树都同时遍历完成,且每次比对数值不出错,才可视为两棵树等价。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。