如何在SML

时间:2018-02-14 01:18:30

标签: sml smlnj

我有两种数据类型:

datatype 'a Tree = LEAF of 'a | NODE of ('a Tree) * ('a Tree)

datatype 'a myTree = myLEAF of 'a | myNODE of 'a * 'a * 'a myTree * 'a myTree

有了这两个,我需要能够找到树的最小值和最大值。

例如:

findMin (NODE(NODE(LEAF(5),NODE(LEAF(6),LEAF(8))),LEAF(4)))

将产生4。

我已经做了一段时间了,我很困惑。

任何指导都会有所帮助。谢谢。

3 个答案:

答案 0 :(得分:2)

您知道每个'树中至少有一个元素,因此始终存在最小/最大值。

在两个构造函数LEAFNODE中的每一个上使用模式匹配,并在NODE情况下使用递归,因为两个分支可能具有不同的最小值/最大值和最小值节点的/ max由其分支的最小值/最大值确定。如果您正在查找树的最小/最大整数,请使用内置辅助函数Int.minInt.max。 (你的例子表明情况确实如此。)

fun findMin (LEAF x) = (* ... *)
  | findMin (NODE (leftTree, rightTree)) =
    let (* ... use findMin recursively on each branch ... *)
    in (* ... find the minimal value of the two branches ... *)
    end

我不确定&#39; myTree 类型的优点:它是二叉树,因为它有两个&#39; myTree < / em>每个节点的分支,但每个节点还有两个&#39; a 元素?您是否有兴趣找到这些值的 的最小值/最大值?或者是一个键和另一个基于树的字典结构中的值?如果是这样,那么为什么&#39; a - &gt; &#39; a 而非&#39; a - &gt; &#39,B ?当你不理解问题陈述时,很难解决问题,而数据类型是其中很大一部分。

修改:由于您自己提供了解决方案,请允许我提供一些反馈:

fun findMin (LEAF(v)) = v
  | findMin (NODE(left, right)) =
      if findMin(left) < findMin(right)
      then findMin(left)
      else findMin(right)

这种解决方案效率非常低,因为它为每个节点的整个子树调用了三次。这意味着函数调用的数量大致遵循recurrence relation f(0)= 1 f(n)= 3·f(n-1)。这相当于 3 n 或指数多次调用以查找 n 元素列表中的最小元素。

  • 这是一种通过临时存储您使用两次的结果来获取线性时间的方法:

    fun findMin (LEAF v) = v
      | findMin (NODE (left, right)) =
        let val minLeft = findMin left
            val minRight = findMin right
        in if minLeft < minRight then minLeft else minRight
        end
    

    没有理由执行在树的每个节点中多次计算findMin leftfindMin right的艰巨任务。由于我们多次引用它, let-in-end 是一种简单的方法,可以将结果绑定到词法范围的名称minLeft和{{1 }}

  • 表达式minRight实际上在标准库中有一个名称:if minLeft < minRight then minLeft else minRight。所以我们可以这样做:

    Int.min
  • 但是使用 let-in-end 的原因实际上已经消失了,因为在图书馆功能的帮助下,我们现在只提到{{1现在,(又名fun findMin (LEAF v) = v | findMin (NODE (left, right)) = let val minLeft = findMin left val minRight = findMin right in Int.min (minLeft, minRight) end )和findMin left(又名minLeft一次。 (实际上,我们不止一次地引用它们,但它位于findMin right内,其中绑定到临时的词法范围名称。)

    所以我们放弃了 let-in-end 更短的时间:

    minRight

    在任何情况下,这些都是同样最优的:它们仅对树中的 n 元素使用 n 递归函数调用,这是您在元素没有排序。现在,如果你知道,那么较小的元素总是在左边,你有binary search tree,你可以更快地找到最小/最大值。 : - )

编辑(再次):为了好玩,您可以同时找到最小/最大值:

Int.min

答案 1 :(得分:1)

我认为一个问题是你正在考虑如何遍历树并按某种顺序检查所有节点并跟踪事物,但递归会为你处理。

你的树有两个案例;它既可以是叶子,也可以是带有两个子树的节点 这表明该解决方案还将有两种情况:一种用于叶子,一种用于内部节点。

记下(用你自己的话,不是代码)你如何找到

中的最小值
  1. 一片叶子;和
  2. 内部节点如果你已经知道其子树的相应最小值 - 不要担心如何找到它们,但假装你知道它们是什么。
  3. 然后写下你如何找到内部节点的子树的最小值 (这是一个递归,所以在你开始思考它之前,你已经解决了这个问题。)

    然后你把它翻译成ML。

答案 2 :(得分:1)

我100%只是过分思考这个问题。谢谢你们的帮助!我得到了答案。

fun findMin (LEAF(v)) = v
  | findMin (NODE(left, right)) =
      if findMin(left) < findMin(right)
      then findMin(left)
      else findMin(right)

fun findMax (LEAF(v)) = v
  | findMax (NODE(left, right)) =
      if findMax(left) > findMax(right)
      then findMax(left)
      else findMax(right)