考虑二叉树:
我们有以下三个操作:
我需要一种算法,使用这些操作给出给定树的所有可能的排列。任何操作都可以应用于任何子树。对于排列,我的意思是任何具有完全相同的叶子集的树。这可能不是很困难,但我似乎无法弄明白。
[编辑]叶子也可以是名称(即变量),因此不能选择依赖于它们的属性作为整数。树确实代表了总和。
[Edit2]这个练习的目的是通过查找 A 和 -A 形式的术语来减少总和,调整树以使它们成为子树(+ A -A )以消除它们。上面的三个操作是我系统中的公理,它们需要一直使用,否则无法证明简化树等于原始树。由于我使用的是Twelf逻辑编程语言,如果我能找出算法来做我最初提出的问题,其余的就很容易了,但其他解决方案当然是受欢迎的。
答案 0 :(得分:2)
似乎最简单的解决方案是对树进行深度优先遍历,将所有节点收集到列表中,生成列表的所有排列,将每个排列转储到二叉树中。
所以,给定列表(+ a(+ b c)),我们有节点[a; b; c],具有以下排列:
[a; b; c]
[a; c; b]
[b; a; c]
[b; c; a]
[c; a; b]
[c; b; a]
列表中的第一项是您的头,以下两项是子节点,接下来的四项是子子节点,依此类推。
如果您需要生成所有可能树的列表,而不仅仅是平衡树,则此increases dramatically的复杂性。在这种情况下,您需要将它们分组:
[a; b; c; d]
[(a; b); c; d]
[(a; b; c); d]
[a; (b; c); d]
[a; (b; c; d)]
[a; b; (c; d)]
[a; b; d; c]
// first permutation
[(a; b); d; c]
[(a; b; d); c]
...
每个n元组是一组节点。对于多个节点,宇宙将在算法完成之前经历热死亡。
答案 1 :(得分:1)
这个问题的解决方案无疑将包含Catalan numbers。 C n -1 可能存在 n 叶子的二叉树,并且有 n !可能的叶子排序,所以有 n ! * C n -1 可能的树。但是,枚举它们会稍微复杂一些。
答案 2 :(得分:1)
这些操作类似于具有以下属性的添加:闭包,关联性,交换性。对于匹配节点,每个叶子都保持相同的叶子集合,并且可以以递归方式应用。计算给定节点x的排列(在Haskell和F#的一些奇怪混合中)
let count x = match x with
| LeafNode -> 1
| TreeNode (a,b) -> 2 * count a * count b
答案 3 :(得分:1)
你有结社性和交换性,所以你可以自由地移动元素。 解决此问题的实用方法如下:
将树梳到一边,就会得到一个清单。
对列表进行排序,以便应取消的元素彼此相邻。
将元素移动到子树中并取消。
要获得所需的证明,您必须为这些操作构建小样本,然后将其组合起来。
或者你可以查找AC匹配。
按照你的建议尝试所有排列只会让你发生一次大的组合爆炸。
答案 4 :(得分:1)
正如所指出的,如果你真的有交换性和相关性公理,那么最好只收集加数并将它们作为一组或一个列表处理。
如果这不令人满意,接下来要注意的是,实际上你似乎并不需要所有排列,但你想重写你的表达式以简化它们。这可以比制作所有排列更有效!
然而,要重复:),如果你只有交换性和关联性,请处理集合中的术语。
答案 5 :(得分:0)
我发现了解决树木减少的根本问题的解决方案:
正如所建议的那样,另一种方法是首先将树转换为列表:(+ A(+ B(+ ...))X),然后找到匹配的对A和-A并将它们带入到达顶点。我怀疑这可能会产生比上述算法更长的证据(这是不可取的),尽管我还没有尝试过。
尽管如此,我发现原始问题引人入胜,我想尝试一下基于此的算法如何与上述算法进行比较。