以功能方式遍历树

vic*_*aba 1 algorithm tree functional-programming scala data-structures

我已经在Scala中实现了一个基本的可变树,我想以一种功能性的方式遍历它以便搜索元素,但是我不知道如何实现它。我还希望该算法尽可能地尾部递归。

树是具有值和也是树的叶子列表的结构。

任何帮助,将不胜感激。

这是我的代码(专注于getOpt方法):

package main

import scala.collection.mutable.ListBuffer

sealed trait Tree[Node] {

  val node: Node

  val parent: Option[Tree[Node]]

  val children: ListBuffer[Tree[Node]]

  def add(n: Node): Tree[Node]

  def size: Int

  def getOpt(p: (Node) => Boolean): Option[Tree[Node]]

  override def toString = {
    s"""[$node${if (children.isEmpty) "" else s", Children: $children"}]"""
  }
}

case class ConcreteTree(override val node: Int) extends Tree[Int] {

  override val children = ListBuffer[Tree[Int]]()

  override val parent: Option[Tree[Int]] = None

  override def add(n: Int): ConcreteTree = {
    val newNode = new ConcreteTree(n) {override val parent: Option[Tree[Int]] = Some(this)}
    children += newNode
    newNode
  }

  override def size: Int = {
    def _size(t: Tree[Int]): Int = {
      1 + t.children.foldLeft(0)((sum, tree) => sum + _size(tree))
    }
    _size(this)
  }

  // This method is not correct
  override def getOpt(p: (Int) => Boolean): Option[Tree[Int]] = {
    def _getOpt(tree: Tree[Int], p: (Int) => Boolean): Option[Tree[Int]] = {
      tree.children.map {
        t =>
          if(p(t.node)) Some(t) else t.children.map(_getOpt(_, p))
      }
    }
  }
}

object Main {

  def main(args: Array[String]) {
    val tree1 = ConcreteTree(1)
    val tree2 = tree1.add(2)
    val tree3 = tree1.add(3)

    println(tree1.getOpt(_ == 2))
  }
}
Run Code Online (Sandbox Code Playgroud)

@doertsch答案是我目前拥有的最佳方法。

Kar*_*ldt 5

实际上,我会寻求一些更灵活的方法,并实现一个泛型函数来生成扁平化树的惰性流,那么以后的许多工作将变得更加容易。像这样:

def traverse[Node](tree: Tree[Node]): Stream[Tree[Node]] = 
  tree #:: (tree.children map traverse).fold(Stream.Empty)(_ ++ _)
Run Code Online (Sandbox Code Playgroud)

然后,您getOpt可以简化为:

override def getOpt(p: (Int) => Boolean): Option[Tree[Int]] =
  traverse(tree) find {x => p(x.node)}
Run Code Online (Sandbox Code Playgroud)

进一步简化,如果您只是对没有Tree结构的数据感兴趣,则可以获取节点流,从而获得:

def nodes[Node](tree: Tree[Node]): Stream[Node] = traverse(tree) map (_.node)

def getNode(p: (Int) => Boolean): Option[Int] = nodes(tree) find p
Run Code Online (Sandbox Code Playgroud)

这就为非常简洁可读的代码像其他的可能性nodes(tree) filter (_ > 3)nodes(tree).sumnodes(tree) contains 12,和类似的表述。