在Scala中合并二叉树

时间:2014-05-24 20:59:22

标签: algorithm scala merge functional-programming binary-tree

它说here

  

合并两个二叉树的最简单方法是迭代迭代   留下一棵树的孩子,直到到达没有左孩子的节点。   然后将另一棵树的根添加为左子。

易。在"普通代码"中,我写了这样的东西:

if(!left.isEmpty)
  thisFuncAgain()
else left = otherSet; return this

然而,我无法想象Scala会如何看待它。以下是我的一些想法。此函数将放在BinaryTree类:

def merg(that: BinaryTree): BinaryTree = {
  if(leftNode.isEmpty) leftNode += that; leftNode
  else merg(leftNode)
}

但是,无法重新分配到val。我可以为左节点递归此函数,但是当它返回时,将不考虑最后一个节点之前的元素。

关于我怎么想到这个的任何提示? 我是Scala的初学者,我真的坚持这一点。

1 个答案:

答案 0 :(得分:2)

这取决于BinaryTree类的外观,而且你没有说清楚。完全可以使用可变BinaryTree,您可以在其中修改节点。但是这里有一个使用典型的不可变BinaryTree

的算法实现
sealed trait BinaryTree[A] {
  def merge(that: BinaryTree[A]): BinaryTree[A]
}
case object Empty extends BinaryTree[Nothing] {
  def merge(that: BinaryTree[A]: BinaryTree[A] = that
}
case class Node(left: BinaryTree[A], value: A, right: BinaryTree[A]) 
extends BinaryTree[A] {
  def merge(that: BinaryTree[A]): BinaryTree[A] =
   Node(left.merge(that), value, right)
}

它不会修改this,它会返回BinaryTree的新实例,并保持this不变。它并不昂贵,因为that的所有节点和this的大多数节点将在两棵树之间共享。需要重新创建的唯一节点位于此根节点及其最左侧节点之间。你获得了不变性的好处,最重要的是它可以自由分享,你永远不需要制作防御性副本。

另一方面,很有可能使左右儿童var而不是val并且合并变异原始树。


您在评论中说明它只返回要合并的树。它不是。我刚刚修复了Node.merge中的拼写错误,也许这让你很困惑。 Mabye让你困惑的是,返回通常不是scala。在合并的两个实现中,您可以放置​​一个返回return thatreturn Node(left.merge...,这意味着完全相同的事情。此外,return Node(...)return new Node(...)相同。无论如何,这是它的工作原理

假设值是整数,this

    5
   / \
  7   C
 / \
2   B
 \
  A

ABC可能是单个节点,整个树木都是空的,我们不在乎,关键是2的左边孩子是空的这是合并的地方。

that只是M,因为它包含的内容并不重要。我们走吧。

thisNode([node 7], 5, C)

我们称之为合并:

Node([node 7], 5, C).merge(M)

返回

Node([node 7].merge(M), 5, C)

关键是此代码不会返回this。它返回一个新节点,其中左子节点不是原始节点中的节点。它不再是[node 7],而是[node 7].merge(M)。因此,让我们计算[node 7].merge(M)[node 7]Node([node 2], 7, B)。让我们把M合并到那里。

[node 7].merge(M) = Node([node 2], 7, B).merge(M) 
                  = Node([node2].merge(M), 7, B). 

同样,在返回的节点中,我们替换了左子节点。再一次:[node2]是Node(Empty,2,A),所以:

[node 2].merge(M) = Node(Empty, 2, A).merge(M) 
                  = Node(Empty.merge(M), 2, A). 

现在我们到底了。 Empty.merge(M)M。我们只需要倒带,所有人都会到位。

[node 2].merge(M) = Node(Empty, 2, A).merge(M) 
                  = Node(Empty.merge(M), 2, A) 
                  = Node(M, 2, A)

    2
   / \
  M   A

如你所见,我们实际上已经做了一些事情。结果中M小于2。

又迈进了一步:

[node 7].merge(m) = Node([node 2], 7, B).merge(M) 
                  = Node([Node 2].merge(M), 7, B). 

现在我们知道[node2] .merge(M)的含义。所以

Node([node 2], 7, B).merge(M) = Node(Node(M, 2, A), 7, B)

    7
   / \
  2   B
 / \
M   A

我们有[node 7] .merge(m),所以我们可以计算最终结果:

this.merge(m) = Node([node 7].merge(m), 5, C)

我们知道[node 7].merge(m)是什么,所以最终结果如预期的那样:

        5
       / \
      7   C
     / \
    2   B
   / \
  M   A