Haskell 查找树中节点的最大值
我有个问题 我必须在Haskell中实现一个函数Haskell 查找树中节点的最大值,haskell,binary-tree,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)) 这是对的吗?让我们看看要证明这是正确的有多难。为什么?因为这是分析程序错误
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))
这是对的吗?让我们看看要证明这是正确的有多难。为什么?因为这是分析程序错误的好方法。尤其是递归的。从技术上讲,我们将使用归纳法,但它并不复杂。关键是要认识到
maxtt
必须始终是树中的最大值t
——这个声明,“maxtt
必须始终是树中的最大值t
”被称为不变量,我们将尝试证明它
首先,我们假设t
是一个Leaf
。在这种情况下,您已经定义了maxT(Leaf a)=a
,并且由于此树中没有其他值,a
必须是最大的。因此,maxT
在传递Leaf
时支持我们的不变量。这就是“基本情况”
<>现在我们将考虑当我们让<代码> T =节点(叶A)B(叶C)某些<代码>整数< /代码> S代码> A <代码> >代码> B>代码>和<代码> C/<代码>。这是一个高度为1的树,形成了一个你可以称之为归纳的“示例案例”。让我们试试
maxT
,看看不变量是否成立
maxT t
===
maxT (Node (Leaf a) b (Leaf c))
===
max b (max (maxT (Leaf a)) (maxT (Leaf c)))
此时,我们将使用我们的基本情况步骤,并说,由于此表达式中的maxT
的唯一应用程序位于Leaf
s上,因此每个应用程序都必须支持我们的不变量。这有点愚蠢,但那只是一个例子。稍后我们将看到更一般的模式
现在,让我们计算maxT(Leaf)
位,知道结果是每个特定的左或右子树中的最大值
===
max b (max a c)
现在,我不太想深入讨论max
的定义,但基于它的名称,我很高兴假设max a b
返回的值在a
和b
之间最大。我们可以在这里选择详细信息,但很明显,max b(max a c)
已经获得了有关节点的所有相关信息,用于计算整个height-1树的最大值。我认为这是一个成功的证明,maxT
对height-0和height-1树都有效(Leaf
s和Node
s只包含Leaf
s)
下一步是概括这个例子
让我们在树的高度上应用同样的模式。我们将询问如果我们固定一些数字,n
,并假设maxtt
对高度n
或更低的所有t
保持不变,会发生什么。这有点奇怪,我们只展示了这对n=0
和n=1
有效。稍后会很清楚为什么会这样
那么这个假设对我们有什么作用呢?好的,让我们取任意两棵高度小于等于n的树(称它们为l和r),任意整数x,并将它们组合成一棵新树。当我们执行maxtt
时会发生什么
maxT t
===
maxT (Node x l r)
===
max x (max (maxT l) (maxT r))
我们知道,根据我们的假设,maxtl
和maxtr
支持我们的不变量。然后,max
es链继续支持我们现在对树t
的不变量,即高度-(n+1)
。此外(这非常重要)我们组装新的树的过程是通用的,我们可以用这种方法制作任意高度的(n+1)
树。这意味着maxT
适用于任何高度-(n+1)
树
诱导时间!我们现在知道,如果我们选择一个n
,并且(出于某种原因)相信maxT
适用于任何高度-n
树,那么它必须立即适用于任何高度-(n+1)
树。让我们选择n=0
。通过“基本情况”我们知道maxT
适用于Leaf
s,因此我们突然知道maxT
适用于高度-1
树。这就是我们的“案例”。现在,根据这些知识,我们可以立即看到maxT
适用于高度-2
树。然后是高度-3棵树。然后是高度-4
。等等等等
这就完成了maxT
正确性的证明*
*我必须留下一些警告。我们并没有真正做精细的细节来说明max
链是可行的,尽管这是有道理的。我也没有真正证明归纳步骤是有效的,如果有更多的方法来创建一个高度-(n+1)
树,而不仅仅是在高度-n
或更小的树上使用节点,会怎么样?更有效的方法是“拆开”一棵高的树,但我认为这更难看到。最后,我们想认真考虑一下,如果我们发送maxT(Leaf undefined)
或其他类似的病理值,会发生什么。这些出现在Haskell中,因为它是一种(图灵完整的)计算机语言,而不是纯数学。老实说,对于您的情况来说,这些小细节不会有太大的改变。这不是最完美的实现,但在我看来,它应该可以工作。你能详细说明一下你认为它有什么问题吗?你可能想把它的类型概括为maxT::Ord a=>Tree a->a
,但除此之外,它看起来还不错。你试过测试它吗?试试这个:maxT(节点(叶1)5(叶(-4)))2(节点(叶6)2(叶4))
。你没有问题!