在树中查找节点的最大值

时间:2013-05-19 12:26:09

标签: haskell binary-tree

我有一个问题。

我必须在Haskell中实现一个函数maxT,它从二叉树中返回一个节点的最大值。

data Tree a = Leaf a | Node (Tree a) a (Tree a)

这是给出的。接下来我该怎么办?

maxT :: (Tree Integer) -> Integer
maxT (Leaf a) = a
maxT (Node l a r) = max a (max (maxT l) (maxT r))

这是对的吗?

1 个答案:

答案 0 :(得分:4)

让我们看看证明正确有多难。为什么?因为这是分析程序错误的好方法。特别是递归的。我们在技术上会使用感应,但它并不复杂。关键是要认识到maxT t必须始终是树t中的最大值 - 此声明“maxT t必须始终是树t中的最大值”被称为不变量,我们将尝试证明它。

首先,我们假设tLeaf。在这种情况下,您已定义maxT (Leaf a) = a,并且由于此树中确实存在没有其他值,因此a 必须是最大的。因此,maxT在通过Leaf时支持我们的不变量。这是“基本情况”。


现在,我们会考虑当t = Node (Leaf a) b (Leaf c) Integer a bcmaxT出现maxT t === maxT (Node (Leaf a) b (Leaf c)) === max b (max (maxT (Leaf a)) (maxT (Leaf c))) 时会发生什么。这是一个高度为1的树,形成了你可能称之为“示例案例”的感应。让我们试试maxT,看看不变量是否成立。

Leaf

此时我们将使用我们的基础案例步骤,并说由于此maxT (Leaf _)=== max b (max a c) 的唯一应用程序位于max s上,因此每个应用程序都必须支持我们的不变量。这有点愚蠢,但那是因为它只是一个例子。我们稍后会看到更一般的模式。

现在,让我们评估我们的max a b位,知道结果是每个特定左子树或右子树的最大值。

a

现在,我不想深入研究b的定义,但根据其名称,我很高兴地假设max b (max a c)返回{{1}之间的最大值}和Node。我们可以在这里详细介绍细节,但很明显maxT已经获得了有关我们Leaf的所有相关信息,用于计算整个高度-1树的最大值。我称之为Node适用于height-0和height-1树(Leaf s和n仅包含maxT t s)的成功证明。< / p>

下一步是概括这个示例案例。


因此,让我们应用相同的模式来推广树的高度。我们会问,如果我们修正了一些数字t会发生什么,并假设n维持我们对所有n = 0高度n = 1或更低的不变量的不变量。这有点奇怪 - 我们只展示了Treen的作品。很明显为什么这会稍晚起作用。

那么这个假设对我们有什么影响?好吧,让我们取两个l个高度r或更少(称为xt = Node x l r),任意整数maxT t,并将它们组合成一个一棵新树maxT t === maxT (Node x l r) === max x (max (maxT l) (maxT r)) 。当我们maxT l时会发生什么?

maxT r

我们知道,根据我们的假设,maxt支持我们的不变量。然后,(n+1) es的链继续维持我们的不变量,因为树Tree的高度为(n+1)。此外(这非常重要)我们组装新maxT的过程是通用的 - 我们可以在此方法中生成任何高度 - (n+1)树。这意味着n适用于任何高度 - maxT树。


感应时间!我们现在知道,如果我们选择n并且相信(出于某种原因)(n+1)适用于任何高度 - n = 0树,那么它必须立即适用于任何高度 - {{1树。我们选择maxT。我们知道Leaf适用于maxT的“基本情况”,所以突然我们知道1适用于高度 - maxT树。这是我们的“案例”。现在,鉴于这些知识,我们可以立即看到2适用于高度 - 3树。然后是高度 - 4树。然后是身高 - maxT。等等,等等。

这样就完成了max正确的证明*。

*我必须留下一些警告。虽然有意义,但我们并没有真正做出精确的细节来证明(n+1)链是有效的。我也没有真正证明诱导步骤有效 - 如果有更多的方法来制作高度 - Node树而不仅仅是在高度上使用n - n或更小的树?更强大的方法是“分开”一个高度 - maxT (Leaf undefined)树,但我觉得这有点难以辨认。最后,如果我们发送{{1}}或其他类似的病态值,我们真的想要认真思考会发生什么。这些出现在Haskell中,因为它是一种(图灵完备的)计算机语言而不是纯数学。老实说,这些小小的东西对你的情况并没有太大的改变。