两个二叉树返回一个布尔值

时间:2013-06-09 23:32:08

标签: haskell

此函数返回的值的含义是什么?您可以使用图表来解释是否需要

data Tree a = Empty_Tree | Node {element :: a, left_tree,right_tree :: Tree a}
gurgle :: Tree a -> Tree a -> Bool
gurgle tree_a tree_b = case (tree_a, tree_b) of
      (Empty_Tree , Empty_Tree ) -> True
      (Empty_Tree , _ ) -> False
      (_ , Empty_Tree ) -> False
      (Node _ left_a right_a, Node _ left_b right_b) -> gurgle left_a right_b
                                                        && gurgle right_a left_b

1 个答案:

答案 0 :(得分:6)

让我们画出来。首先,我将在空树上使用小圆圈,在节点上使用圆圈表示数据,并为子树使用两个分支。 leftright本身也是树木。

example simple trees

好的,让我们逐行获取代码并将case语句解压缩到顶层的模式匹配中,因为

function x y = case (x,y) of
    (0,1) -> this
    (1,10) -> that

可以写

function 0 1 = this
function 1 10 = that

gurgle Empty_Tree Empty_Tree = True

base case

在这里学到很多东西 - 如果它们都是空的那就是肯定的。行。

gurgle Empty_Tree _ = False

这意味着我们得到像

这样的东西

empty,notempty gives False

因为无论第二个参数是什么,它都会给出False。我们已经消除了第二个参数在最后一行是Empty_Tree的情况,所以第二个参数必须是非空的,在这里给出False。

下一行非常喜欢它,只是相反:

gurgle _ Empty_Tree = False

再次,像这样的东西

nonempty, empty gives false

得到一个否定答案。我开始怀疑,一旦我读完这两行,它就会检查两棵树的形状是否相同。

递归案例

gurgle x y = gurgle(left_tree x)(right_tree y)&& gurgle(right_tree x)(left_tree y)

这是最有趣的一个。注意它正在做的交换方面的事情。它不只是检查两者的子树是否相同,而是从右侧与左侧进行比较。

not matched

还要注意它忽略了节点的值 - 这就是为什么我在这个例子中删除了数字。

我们需要做什么才能成为真的?

为了使其真实,我们需要一个左边的形状以匹配另一个右边的形状:

mirrored trees

你的意思是什么?

递归案例说,一个人的左边必须与另一个人的右边相匹配。当你忽略这些值时,树必须是彼此的镜像。

模式匹配中发生了什么?

原文中的递归案例

   (Node _ left_a right_a, Node _ left_b right_b) -> gurgle left_a right_b
                                                    && gurgle right_a left_b

让我们为该代码着色以匹配上图:

colour coded code

将其着色是一个很好的视觉线索,因为左边的名称left_a等并不意味着什么特别的,它们只是指向树的位。

哪些位?

Node _ left_a right_a

这与Node的定义相符:

data Tree a = Empty_Tree | Node {element :: a, left_tree,right_tree :: Tree a}

第一个(灰色)位是元素。 element现在是从树节点到值的函数。

第二个(浅棕色)位是左子树left_tree。它可能很大而且复杂,或只是Empty_Tree。 (它可以是任何树。)

第三个(淡橙色)位是正确的子树right_tree。它们与我的图表匹配:

a tree

我没有在彩色框中添加任何细节 - 它可以是任何树,无论大小。

当您的原始代码将其放在左侧时

colour coded code

它为子树命名,以便它可以直接引用它们,而不是使用left-treeright_tree函数。