给定二叉搜索树,打印形成相同BST的所有输入组合

时间:2014-03-31 12:19:25

标签: data-structures

例如,

输入二叉树是

     2 
3         1 

我们需要为同一个二叉树结构打印所有可能的组合(不需要树平衡)

231,213

注意:123不是有效输出,因为它会改变树结构。

如果模式更长,那就太复杂了。

另一个例子

         5 
      3     7
   2    4  6   8

在这种情况下

5 3 7 2 4 6 8

5 3 2 4 7 6 8

5 7 3 2 4 6 8

...............

我想知道是否有任何算法可以找到给出相同二叉树的模式。

4 个答案:

答案 0 :(得分:1)

这个问题比在表面看起来更难。

考虑第一个例子中的树:

  2
1   3

正如您所说,输入有两种可能的排序方式:2,1,32,3,1。规则是:root,然后是任何顺序的子项。

但这太容易了。要查看问题的完整复杂性,您必须将其扩展到另一个级别。因此,你的第二个例子:

      5 
   3     7
2    4  6   8

通常有两种方法来构造这个树:广度优先,或深度优先。要先做广告,你首先重复应用" root,然后按任意顺序应用子项#34;规则。因此:

5,3,7,2,4,6,8
5,3,7,2,4,8,6
5,3,7,2,6,4,8
...
5,7,3,8,6,4,2

每个级别都有(2 ^ k)!排列,其中k是级别。所以在根处有1个排列,在第二级有两个排列(k == 1),在下一个级别有24个排列等等。

但首先执行此广度不会生成所有可能的有效输入。例如,5,3,2,4,7,6,8完全有效。要获得所有有效输入,您还必须包括深度优先构造。事情变得有趣。

您可以生成树的预先遍历:5,3,2,4,7,6,8或反向预订遍历:5,7,6,8,3,2,4。这里的规则是root,然后以任何顺序遍历子深度优先。

但这并不能涵盖5,3,2,7,8,4,6的奇怪情况,这种情况只会跳过,但会确保节点的父节点在其子节点之前提供。

我没有完整的解决方案,但我可以给你一个算法的开头。考虑随机生成有效输入序列的情况。你可以用循环来做到这一点:

nodes_array = create an array of nodes that can be selected
output_array = array of selected nodes

add root to nodes_array
while nodes_array is not empty
    temp = randomly select node from nodes_array, and remove it
    if temp.left != null
        add temp.left to nodes_array
    if temp.right != null
        add temp.right to nodes_array
    append temp to output_array
end while

应始终生成有效输入,因为子节点永远不会添加到输出数组中,除非已经选择了父节点。

然后,生成所有有效组合的问题成为改变随机选择步骤的问题,以便在每个级别生成nodes_array的所有可能的排列。生成排列是一个已解决的问题。但是,递归地应用它会需要一些思考。

答案 1 :(得分:0)

这是一个在Python中使用回溯的简单算法。它假定使用insert操作实现二叉搜索树。每个节点的值均为node.value,可能是node.leftnode.right的子项。

def get_children(node):
    children = []
    if node.left is not None:
        children.append(node.left)
    if node.right is not None:
        children.append(node.right)
    return children

def print_permutations(possibilities, string):
    if len(possibilities) == 0:
        print(string)
        return

    for i in range(len(possibilities)):
        node = possibilities[i]
        del possibilities[i]
        new_possibilities = get_children(node) + possibilities
        print_permutations(new_possibilities, string + " " + str(node.value))
        possibilities.insert(i, node)

我们的想法是,每次从下一个号码的可能候选人列表中选择一个节点时,您都​​会将该节点的子节点添加到可能的候选者列表中。一旦没有更多候选人,您就可以获得一个可能的订单。

您可以这样称呼它:

b = BinarySearchTree()
b.insert(5)
b.insert(3)
b.insert(7)
b.insert(2)
b.insert(4)
b.insert(6)
b.insert(8)

print_permutations(get_children(b.root), str(b.root.value))

它会输出:

5 3 2 4 7 6 8
5 3 2 4 7 8 6
5 3 2 7 6 8 4
5 3 2 7 6 4 8
5 3 2 7 8 6 4
...

答案 2 :(得分:0)

我采用了一种非常简单的方法:使用递归按以下顺序打印节点:root>left child>right child

请注意:另一个有效序列:root> right child> left child 同样可以打印。 为简单起见,我在这里给出第一种有效序列类型的代码。

这是我的代码:

class Node: 
  
    # Constructor to create a new node 
    def __init__(self, data): 
        self.data = data 
        self.left = None
        self.right = None

root = Node(20) 
root.left = Node(8) 
root.right = Node(22) 
root.left.left = Node(4) 
root.left.right = Node(12) 
root.left.right.left = Node(10) 
root.left.right.right = Node(14)

问题所在:

def printNodes(root):
    
    if root == None:
        return False
    else:
        print(root.data)
        printNodes(root.left)
        printNodes(root.right)

输出:

printNodes(root)

20
8
4
12
10
14
22

答案 3 :(得分:0)

@deleterOfWorlds 的回答有效,但他使用了一个需要线性时间进行插入和删除的列表。这是我的 Python 解决方案,并附有大量解释。

我们通过从该位置的一组可能选择中为每个位置选择一个节点来从左到右构建每个数组。我们将节点值添加到路径中,并将节点的子节点(如果有)添加到可能性列表中,然后进一步递归。当没有进一步的选择时,我们有一个候选数组。为了生成其余的数组,我们回溯直到我们可以做出不同的选择并再次递归。

问题在于使用合适的数据结构来保存可能性。列表有效,但是在回溯时必须将节点放回先前的位置(顺序很重要,因为我们添加了必须在节点之后访问的节点的子节点)。从列表中插入和删除需要线性时间。集合不起作用,因为它不维护顺序。 dict 效果最好,因为 Python 字典会记住插入顺序并且所有操作都在恒定时间内运行。

def bst_seq(root: TreeNode) -> list[list[int]]:
    def _loop(choices: MutableMapping[TreeNode, bool], path: list[int], result: list[list[int]]) -> None:
        if not choices:
            result.append([*path])
        else:
            # Take a snapshot of the keys to avoid concurrent modification exception
            for choice in list(choices.keys()):
                del choices[choice]
                children = list(filter(None, [choice.left, choice.right]))
                for child in children:
                    choices[child] = False
                path.append(choice.val)
                _loop(choices, path, result)
                path.pop()
                choices[choice] = False
                for child in children:
                    del choices[child]

    result = []
    _loop({root: False}, [], result)
    return result
相关问题