algorithm - 树中的最大元素

标签 algorithm scala recursion recursive-datastructures

我在 Scala 中有以下 ADT 实现。

如何找到树中的最大元素?我可以引入一些辅助函数吗?如果可以,那么如何引入?

abstract class MySet {
  def max: Int

  def contains(tweet: Tweet): Boolean = false
}

class Empty extends MySet {
  def max: throw new NoSuchElementExeption("max called on empty tree")

  def contains(x: Int): Boolean =
    if (x < elem) left.contains(x)
    else if (elem < x) right.contains(x)
    else true
}

class Node(elem: Int, left: MySet, right: MySet) extends Set {
  def max: { ... }

  def contains(x: Int): Boolean =
    if (x < elem) left.contains(x)
    else if (elem < x) right.contains(x)
    else true
}

我在 Haskell 中找到了一个感觉非常直观的解决方案,我能以某种方式将它转换为 Scala 吗?

data Tree a = Nil | Node a (Tree a) (Tree a)
maxElement Nil = error "maxElement called on empty tree"
maxElement (Node x Nil Nil) = x
maxElement (Node x Nil r) = max x (maxElement r)
maxElement (Node x l Nil) = max x (maxElement l)
maxElement (Node x l r) = maximum [x, maxElement l, maxElement r]

更新

我对在 Scala 中复制 Haskell 代码不感兴趣,相反我认为 Haskell 版本更直观,但因为 this 关键字和面向对象语言中的其他内容。如何在没有模式匹配的情况下以面向对象的风格编写等效代码?

最佳答案

您的树是异构的,这意味着每个节点可以是具有值的完整节点,也可以是空叶。因此你需要区分哪个是哪个,否则你可以在空节点上调用 max。有很多方法:

经典 OOP:

abstract class MySet {
  def isEmpty: Boolean
  ...
}

class Empty extends MySet {
  def isEmpty = true
  ...
}

class Node(...) extends MySet {
  def isEmpty = false
  ...
}

所以你做这样的事情:

var maxElem = elem
if(!left.isEmpty)
  maxElem = maxElem.max(left.max)
end
if(!right.isEmpty)
  maxElem = maxElem.max(right.max)
end

由于 JVM 在运行时有类信息,因此您可以跳过 isEmpty 的定义:

var maxElem = elem
if(left.isInstanceOf[Node])
  maxElem = maxElem.max(left.asInstanceOf[Node].max)
end
if(left.isInstanceOf[Node])
  maxElem = maxElem.max(right.asInstanceOf[Node].max)
end

(如果您在 MySet 中定义了 max,则不需要 asInstanceOf,但此模式涵盖了您没有定义的情况)

好吧,Scala 为后者提供了一个语法糖,毫不奇怪,它就是模式匹配:

var maxElem = elem
left match {
  case node: Node =>
    maxElem = maxElem.max(node.max)
  case _ =>
}
right match {
  case node: Node =>
    maxElem = maxElem.max(node.max)
  case _ =>
}
maxElem

你可以更进一步,写这样的东西:

def max = (left, right) match {
  case (_: Empty, _: Empty) => elem
  case (_: Empty, node: Node)  => elem.max(node.max)
  case (node: Node, _: Empty)  => elem.max(node.max)
  case (leftNode: Node, rightNode: Node)  =>
    elem.max(leftNode.max).max(rightNode.max)
}

关于algorithm - 树中的最大元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39062467/

相关文章:

algorithm - 如何识别代码片段的 Big-O 表示法是否为对数时间 O(logn)?

performance - 递归伪代码的时间复杂度

scala - 在 Traversable 的 foreach 方法中获取当前元素的索引?

C++:为什么我的递归修剪我的数组而不是执行它应该递归地用值填充数组的预期目的?

string - 学习垃圾邮件发送者的名字

c++ - 为什么 std::copy_n 不增加输入迭代器 n 次?

java - Scala - 如何仅循环遍历目录中与特定字符串匹配的文件?

scala - 为什么 Scala 找不到参数 scala.slick.session.Session 的隐式值?

c++ - 数组打印垃圾值

algorithm - 求一个递归算法的复杂度