Go Tour练习#7:遍历树

huangapple go评论91阅读模式
英文:

Go Tour Exercise #7: Walking the tree

问题

我完成了树比较的Go Tour练习(#69),并且能够有效地比较两棵树。

这是代码:

package main

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

// Walk遍历树t,将所有值发送到通道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确定树t1和t2是否包含相同的值。
func Same(t1, t2 *tree.Tree) bool {
	c := make(chan int)
	c2 := make(chan int)
	go Walk(t1, c)
	go Walk(t2, c2)
	for i := 0; i < 10; i++ {
		if <-c != <-c2 {
			return false
		}
	}
	return true
}

func main() {
	fmt.Println(Same(tree.New(1), tree.New(1)))
}

让我困惑的部分是,如果我在Walk函数中交换命令的顺序为:

ch <- t.Value
Walk(t.Right, ch)
Walk(t.Left, ch)

比较就不再起作用了。我尝试打印两次Walk(tree.New(1), c)的结果,奇怪的是第一次调用打印出:

10,5,7,9...

而第二次调用Walk(tree.New(1), c)打印出:

7,9,10,8...

为什么调用相同的函数两次在交换walk命令的顺序时会产生两个不同的输出?

英文:

I completed the go tour exercise for tree comparisons (#69) and was able to effectively compare two trees.

Here is the code

package main

import (
	&quot;fmt&quot;
	&quot;golang.org/x/tour/tree&quot;
)

// 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 &lt;- 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 {
	c := make(chan int)
	c2 := make(chan int)
	go Walk(t1, c)
	go Walk(t2, c2)
	for i := 0; i &lt; 10; i++ {
		if &lt;-c != &lt;-c2 {
			return false
		}
	}
	return true
}

func main() {
	fmt.Println(Same(tree.New(1), tree.New(1)))
}

The part that confuses me is that if I switch around the order of the commands in the walk function to be

    ch &lt;- t.Value
    Walk(t.Right,ch)
    Walk(t.Left,ch)

the comparison no longer works. I tried printing out the results of Walk(tree.New(1),c) twice and oddly the first call printed

    10,5,7,9...

while the second call of Walk(tree.New(1),c) printed

    7,9,10,8...

Why does calling the same function twice result in two different outputs when switching the order of the walk commands?

答案1

得分: 4

首先,你需要了解树的属性。树的设置是这样的,左边的数字总是小于当前节点的值。右边的数字总是大于当前节点的值。

因此,如果你想找到最小的数字,你只需要在每个节点上向“左”走。如果你去到最小数字的父节点,你就得到了第二小的数字。第二小数字的右子节点可能是第三小的数字,也可能不是。然而,如果你从第二小数字的右子节点开始每次都向左走,你最终会到达第三小的数字。这样做直到遍历完每个节点。

当你遍历树时,实际上是在对数字进行排序。

Walk(t.Left,ch)
ch <- t.Value
Walk(t.Right,ch)

这是先走左边,然后当前节点,最后右边。最小的,第二小的,第三小的。

ch <- t.Value
Walk(t.Right,ch)
Walk(t.Left,ch)

这是当前节点,然后右边,最后左边。第二小的,第三小的,最小的。这种排序的问题在于它们的输出顺序取决于树的顺序。在第一个排序中,树中的元素而不是顺序是重要的。

Walk()函数实际上是实现了树排序算法的一部分。参见:http://en.wikipedia.org/wiki/Tree_sort

英文:

First you need to understand the properties of the tree. The tree is setup so that a number to the Left is always less than the current node's value. A number to the Right is always more.

Therefore, if you wanted to find the smallest number, all you need to do is go "Left" at each node. If you go to the parent of the lowest number, you get the second lowest. The Right child of the second lowest may or may not be the third lowest. However, if you then take a Left at every chance from the Right child of the second lowest, you will end up at the third lowest. This is done until every node has been traversed.

When you Walk() the tree, you are actually sorting the numbers.

Walk(t.Left,ch)
ch &lt;- t.Value
Walk(t.Right,ch)

That goes Left, current, Right. Lowest, second lowest, third lowest.

ch &lt;- t.Value
Walk(t.Right,ch)
Walk(t.Left,ch)

This goes current, Right, Left. Second lowest, third lowest, lowest. The issue with this ordering is that the order they come out depends on the order of the tree. In the first one, the elements in the tree, and not the order, are what mattered.

What the Walk() function is really implementing is a portion of the tree sort algorithm. See: http://en.wikipedia.org/wiki/Tree_sort

答案2

得分: 1

看一下Tree的源代码

// New返回一个新的、随机的二叉树
// 保存着值1k, 2k, ..., nk.
func New(n, k int) *Tree {
    var t *Tree
    for _, v := range rand.Perm(n) {
        t = insert(t, (1+v)*k)
    }
    return t
}

它使用了Perm函数

> Perm返回一个长度为n的整数切片,其中包含了[0,n)的伪随机排列。

你看到的是一个特性:每个由New创建的Tree都是随机的。

英文:

Look at the source code of Tree :

// New returns a new, random binary tree
// holding the values 1k, 2k, ..., nk.
func New(n, k int) *Tree {
	var t *Tree
	for _, v := range rand.Perm(n) {
		t = insert(t, (1+v)*k)
	}
	return t
}

It uses the Perm function :

> Perm returns, as a slice of n ints, a pseudo-random permutation of the
> integers [0,n).

What you see is a feature : each Tree created by New is random.

huangapple
  • 本文由 发表于 2012年8月27日 09:28:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/12135333.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定