在 SML 中查找二叉树的最深元素
Posted
技术标签:
【中文标题】在 SML 中查找二叉树的最深元素【英文标题】:Find the deepest element of a Binary Tree in SML 【发布时间】:2012-10-29 06:49:27 【问题描述】:这是一道作业题。
我的问题很简单:编写一个类型为 'a btree ->' 的函数 btree_deepest ,该列表返回树中最深元素的列表。如果树是空的,那么 deepest 应该返回 []。如果输入树的多个元素处于相同的最大深度,则 deepest 应返回包含这些最深元素的列表,并根据前序遍历进行排序。您的函数必须使用提供的 btree_reduce 函数,并且不能是递归的。
这是我的代码:
(* Binary tree datatype. *)
datatype 'a btree = Leaf | Node of 'a btree * 'a * 'a btree
(* A reduction function. *)
(* btree_reduce : ('b * 'a * 'b -> 'b) -> 'b -> 'a tree -> 'b) *)
fun btree_reduce f b bt =
case bt of
Leaf => b
| Node (l, x, r) => f (btree_reduce f b l, x, btree_reduce f b r)
(* btree_size : 'a btree -> int *)
fun btree_size bt =
btree_reduce (fn(x,a,y) => x+a+y) 1 bt
(* btree_height : 'a btree -> int *)
fun btree_height bt =
btree_reduce (fn(l,n,r) => Int.max(l, r)+1) 0 bt
我知道我必须创建一个函数来传递给 btree_reduce 以构建最深元素的列表,这就是我犹豫不决的地方。
如果允许我使用递归,那么我将只比较左右节点的高度,然后在更高的分支上递归(或者如果它们的高度相同,则在两者上递归),然后在高度时返回当前元素为零并将这些元素放入列表中。
我想我只需要朝着正确的方向努力就可以开始了......
谢谢!
更新:
这是一个无法编译的解决方案的尝试:
fun btree_deepest bt =
let
val (returnMe, height) = btree_reduce (fn((left_ele, left_dep),n,(right_ele, right_dep)) =>
if left_dep = right_dep
then
if left_dep = 0
then ([n], 1)
else ([left_ele::right_ele], left_dep + 1)
else
if left_dep > right_dep
then (left_ele, left_dep+1)
else (right_ele, right_dep+1)
)
([], 0) bt
in
returnMe
end
【问题讨论】:
编译错误,把0, bt
中最后的逗号去掉。
【参考方案1】:
查看了您的代码;看起来 X_ele 是单个元素还是列表存在一些混淆,这会导致类型错误。尝试在上面的第一个“else”分支中使用“@”运算符:
if left_dep = 0
then ([n], 1)
else (left_ele @ right_ele, left_dep + 1)
【讨论】:
我相信你的意思是 [left_ele]@right_ele] 否则它会导致编译错误,因为它返回一个列表。 不,实际上;我的代码按照发布的方式编译(并通过所有包含的测试,如果您在我认为的课程中)。 FWIW,我在上面的'n'周围有方括号,但在left_ele或right_ele周围没有任何地方。这个想法是让它始终返回一个列表,而不是单个元素,也不是列表列表。【参考方案2】:为了获得最大深度的元素,您需要同时跟踪btree_reduce
访问的每个子树的两件事:该子树的最大深度,以及在该深度找到的元素。将这些信息包装在某种数据结构中,您就有了您的类型'b
(根据btree_reduce
的签名)。
现在,当您需要在您提供给btree_reduce
的函数中组合两个子树结果时,您有三种可能的情况:“左”子结果是“更深”、“更浅”或“等深” ”到“右”子结果。记住,子结果代表了每个子树中最深节点的深度和节点值,思考如何将它们组合起来得到当前树的深度和最深节点的值。
如果您需要更多指针,我已经准备好了btree_deepest
的实现,我很想分享它;我还没有发布它,因为你特别(并且很荣幸地)要求提示,而不是解决方案。
【讨论】:
谢谢!我还是有点困惑。我知道因为 SML 是功能性的,它会在开始运行函数'f
之前将所有内容解析为基本情况,并且我的返回类型 'b
将类似于 (r1: list, r2: int)
,其中 r1 是元素列表和r2 高度。我仍然不确定如何将“左”r2 与“右”r2 进行具体比较,然后将“正确”r1 向上传递。 (我想这仍然是问题的核心......)再次感谢您的帮助!
假设您的函数 f
正在使用参数 ((left_elements, left_depth), x, (right_elements, right_depth))
调用。现在,如果是left_depth > right_depth
,则保留left_elements
以获得新结果,并将深度增加1。如果left_depth < right_depth
,反之亦然。如果是left_depth = right_depth
,请结合您的left_elements
和right_elements
列表,因为练习要求返回最大深度的所有元素。
啊,我现在感觉很愚蠢...我已经更新了上面的解决方案尝试,但现在在if left_dep > right_dep then (left_ele, left_dep+1) else (right_ele, right_dep+1)
上给我一个错误,说 if 分支的类型不同意。例如,我只会用 left_elements:int list 声明一个类型,但它必须可互换地处理整数和字符串。我至少在正确的道路上吗?
问题在于另一个if
、if left_dep = 0 then ([n], 1) else ([left_ele::right_ele], left_dep + 1)
:left_ele
和right_ele
都是节点值列表;因此,您不能将 (::
) 一个到另一个上 - 您需要将 (@
) 一个列表附加到另一个列表,并省略列表括号 ([
, ]
) 像这样:if left_dep = 0 then ([n], 1) else (left_ele@right_ele, left_dep + 1)
以上是关于在 SML 中查找二叉树的最深元素的主要内容,如果未能解决你的问题,请参考以下文章
c_cpp 二分搜索是所有以比较为基础的搜索算法时间复杂度最低的算法。用二叉树描速二分查找算法,最坏情况下与二叉树的最高阶相同。比较二叉树线性查找也可用二叉树表示,最坏情况下比较次数为数组元素数量。任