2014-05-24 150 views
1

它说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是不可能的。我可以为左节点递归这个函数,但是当它返回时,最后一个节点之前的元素将不被计算。

关于我怎么能想到这个的任何提示? 我是斯卡拉的初学者,我非常沉迷于此。

+0

我们可以看看你的'BinaryTree'类。 – ggovan

+0

想想它的方式是,你的新的,合并的BinaryTree将与旧的BinaryTree共享节点。 Chris Okasaki的书[_Purely Functional Data Structures_](http://books.google.com/books?id=IV8hAwAAQBAJ)是这种方法的极好来源。令人高兴的是,他的博士学位。本书基于的论文可免费获得[here](http://www.cs.cmu.edu/~rwh/theses/okasaki.pdf)。 –

回答

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中有一个错误,我刚刚修复,也许是你困惑的原因。马布什让你感到困惑的是,返回通常不是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). 

再次,在返回的节点中,我们替换左侧的子节点。再来一次:[节点2]为节点(空,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). 

现在我们知道什么是[节点2] .merge(M)表示。所以

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

    7 
/\ 
    2 B 
/\ 
M A 

我们有[节点7] .merge(M),这样我们就可以计算出最终结果:

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

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

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

新树如何保存所有的值?从我能理解的情况来看,它每次都会递归地循环,直到找到一个空的为止,在这种情况下它会返回要合并的树? – Bula

+0

查看已完成的答案。 –

+0

所以最左边最后会以'that'结尾。这个解释使得它更加清晰。 +1 – Bula