给定BST及其根,打印产生相同bst的所有节点序列

时间:2014-01-19 00:29:54

标签: permutation binary-search-tree sequences

给定BST,找到从root开始的所有节点序列,它们基本上会提供相同的二叉搜索树。

给出一个bst,比如说

  3
 /  \
1    5

答案应该是3,1,5和3,5,1。

另一个例子

       5
     /   \
    4     7
   /     / \
  1     6   10

输出将是

5,4,1,7,6,10

5,4,7,6,10,1

5,7,6,10,4,1

此处的不变量是父母的索引必须始终小于其子项。我很难实现它。

9 个答案:

答案 0 :(得分:14)

我假设你想要一个生成相同BST的所有序列的列表 在这个答案中,我们将使用分而治之
我们将创建一个函数findAllSequences(Node *ptr),它将节点指针作为输入,并返回所有不同的序列,这些序列将生成从ptr挂起的子树。此函数将返回int of Vector of Vector,即vector<vector<int>>包含所有序列。

用于生成序列的主要想法 root必须在其所有子项之前

算法

基础案例1:
如果ptrNULL,则返回一个空序列的向量。

if (ptr == NULL) {
    vector<int> seq;
    vector<vector<int> > v;
    v.push_back(seq);
    return v;
}

基础案例2:
如果ptrleaf node,则返回包含单个序列的向量。它的琐碎是这个序列只包含一个元素,即该节点的值。

if (ptr -> left == NULL && ptr -> right == NULL) {
    vector<int> seq;
    seq.push_back(ptr -> val);
    vector<vector<int> > v;
    v.push_back(seq);
    return v;
}

分割部分这部分非常简单。
我们假设我们有一个可以解决这个问题的函数,因此我们为左子树和右子树解决它。

vector<vector<int> > leftSeq  = findAllSeq(ptr -> left);
vector<vector<int> > rightSeq = findAllSeq(ptr -> right);

合并两个解决方案。(关键在于此步骤。
到目前为止,我们有两套不同的序列:

i. leftSeq  - all sequences in this set will generate left subtree.
ii. rightSeq - all sequences in this set will generate right subtree.

现在左子树中的每个序列都可以与右子树的每个序列合并。在合并时,我们应该注意保留元素的相对顺序。同样在每个合并序列中,我们将在开头添加当前节点的值,因为 root必须在所有子节点之前。

合并的

伪代码

vector<vector<int> > results
for all sequences L in leftSeq
    for all sequences R in rightSeq
        create a vector flags with l.size() 0's and R.size() 1's
        for all permutations of flag
            generate the corresponding merged sequence.
            append the current node's value in beginning
            add this sequence to the results.

return results. 

解释:让我们从集L(of size n)中取一个序列,说出leftSeq,然后从集合R(of size m)中取一个序列,说rightSeq
现在这两个序列可以用 m + n C n 方式合并!
证明:合并后,新序列将包含m + n个元素。由于我们必须维护元素的相对顺序,因此首先我们将在nL个地方的n个地方填充所有(m+n)m元素。剩余的R个位置可以由choose n places from (m+n) places的元素填充。因此,我们必须flags 为此,让我们创建一个布尔向量,说n并用0's m1's 0填充。值为{{1} }表示来自left序列的成员,值1表示来自right序列的成员。剩下的就是生成此标志向量的所有permutations,这可以使用next_permutation来完成。现在,对于每个标志的排列,我们将有一个明确的合并序列LR
例如:L = {1,2,3} R = {4,5}         所以,n=3m=2
因此,我们可以有 3 + 2 C 3 合并序列,即10.
1.now,最初flags = {0 0 0 1 1 },填充 3 0's和< strong> 2 1's
这将导致这个合并的序列:1 2 3 4 5
2.在调用nextPermutation之后我们将有 flags = {0 0 1 0 1 }
这将生成序列:1 2 4 3 5
在打电话给nextPermutation之后我们会有 flags = {0 0 1 1 0}
这将生成序列:1 2 4 5 3
等等 ...

C ++中的代码

vector<vector<int> > findAllSeq(TreeNode *ptr)
{
    if (ptr == NULL) {
        vector<int> seq;
        vector<vector<int> > v;
        v.push_back(seq);
        return v;
    }


    if (ptr -> left == NULL && ptr -> right == NULL) {
        vector<int> seq;
        seq.push_back(ptr -> val);
        vector<vector<int> > v;
        v.push_back(seq);
        return v;
    }

    vector<vector<int> > results, left, right;
    left  = findAllSeq(ptr -> left);
    right = findAllSeq(ptr -> right);
    int size = left[0].size() + right[0].size() + 1;

    vector<bool> flags(left[0].size(), 0);
    for (int k = 0; k < right[0].size(); k++)
        flags.push_back(1);

    for (int i = 0; i < left.size(); i++) {
        for (int j = 0; j < right.size(); j++) {
            do {
                vector<int> tmp(size);
                tmp[0] = ptr -> val;
                int l = 0, r = 0;
                for (int k = 0; k < flags.size(); k++) {
                    tmp[k+1] = (flags[k]) ? right[j][r++] : left[i][l++];
                }
                results.push_back(tmp);
            } while (next_permutation(flags.begin(), flags.end()));
        }
    }

    return results;
}

2017年3月3日更新:如果原始树包含重复项,此解决方案将无法正常运行。

答案 1 :(得分:2)

这是我在Python 3中为您编写的一个清晰,简洁,文档完善的解决方案,希望对您有所帮助!

代码:bst_sequences.py

from binarytree import bst, Node


def weave_lists(first: list, second: list, results: list, prefix: list) -> None:
    """Recursively Weave the first list into the second list and append 
    it to the results list.  The prefix list grows by an element with the 
    depth of the call stack.  Ultimately, either the first or second list will 
    be exhausted and the base case will append a result."""
    # base case
    if not first or not second:
        results.append(prefix + first + second)
        return

    # recursive case
    first_head, first_tail = first[0], first[1:]
    weave_lists(first_tail, second, results, prefix + [first_head])

    second_head, second_tail = second[0], second[1:]
    weave_lists(first, second_tail, results, prefix + [second_head])


def all_sequences(root: Node) -> list:
    """Splits the tree into three lists: prefix, left, and right."""
    if root is None:
        return []

    answer = []
    prefix = [root.value]
    left = all_sequences(root.left) or [[]]
    right = all_sequences(root.right) or [[]]

    # At a minimum, left and right must be a list containing an empty list
    # for the following nested loop
    for i in range(len(left)):
        for j in range(len(right)):
            weaved = []
            weave_lists(left[i], right[j], weaved, prefix)
        answer.extend(weaved)

    return answer


if __name__ == "__main__":
    t = bst(2)
    print(t)
    solution = all_sequences(t)
    for e, item in enumerate(solution):
        print(f"{e:03}: {item}")

示例输出

    __4
   /   \
  1     5
 / \     \
0   2     6

000: [4, 1, 0, 2, 5, 6]
001: [4, 1, 0, 5, 2, 6]
002: [4, 1, 0, 5, 6, 2]
003: [4, 1, 5, 0, 2, 6]
004: [4, 1, 5, 0, 6, 2]
005: [4, 1, 5, 6, 0, 2]
006: [4, 5, 1, 0, 2, 6]
007: [4, 5, 1, 0, 6, 2]
008: [4, 5, 1, 6, 0, 2]
009: [4, 5, 6, 1, 0, 2]
010: [4, 1, 2, 0, 5, 6]
011: [4, 1, 2, 5, 0, 6]
012: [4, 1, 2, 5, 6, 0]
013: [4, 1, 5, 2, 0, 6]
014: [4, 1, 5, 2, 6, 0]
015: [4, 1, 5, 6, 2, 0]
016: [4, 5, 1, 2, 0, 6]
017: [4, 5, 1, 2, 6, 0]
018: [4, 5, 1, 6, 2, 0]
019: [4, 5, 6, 1, 2, 0]

Process finished with exit code 0

答案 2 :(得分:0)

这里是我的python代码,它为同一个BST生成所有元素/数字序列。 对于逻辑,我提到了Gayle Laakmann Mcdowell的编码采访书。

from binarytree import  Node, bst, pprint

def wavelist_list(first, second, wave, prefix):
    if first:
       fl = len(first)
    else:
       fl = 0

    if second:       
        sl = len(second)
    else:
       sl = 0   
    if fl == 0 or sl == 0:
       tmp = list()
       tmp.extend(prefix)
       if first:
          tmp.extend(first)
       if second:   
          tmp.extend(second)
       wave.append(tmp)
       return

    if fl:
        fitem = first.pop(0)
        prefix.append(fitem)
        wavelist_list(first, second, wave, prefix)
        prefix.pop()
        first.insert(0, fitem)

    if sl:
        fitem = second.pop(0)
        prefix.append(fitem)
        wavelist_list(first, second, wave, prefix)
        prefix.pop()
        second.insert(0, fitem)        


def allsequences(root):
    result = list()
    if root == None:
       return result

    prefix = list()
    prefix.append(root.value)

    leftseq = allsequences(root.left)
    rightseq = allsequences(root.right)
    lseq = len(leftseq)
    rseq = len(rightseq)

    if lseq and rseq:
       for i in range(lseq):
          for j in range(rseq):
            wave = list()
            wavelist_list(leftseq[i], rightseq[j], wave, prefix)
            for k in range(len(wave)):
                result.append(wave[k])

    elif lseq:
      for i in range(lseq):
        wave = list()
        wavelist_list(leftseq[i], None, wave, prefix)
        for k in range(len(wave)):
            result.append(wave[k])

    elif rseq:
      for j in range(rseq):
        wave = list()
        wavelist_list(None, rightseq[j], wave, prefix)
        for k in range(len(wave)):
            result.append(wave[k])
   else:
       result.append(prefix) 

   return result



if __name__=="__main__":
    n = int(input("what is height of tree?"))
    my_bst = bst(n)
    pprint(my_bst)

    seq = allsequences(my_bst)
    print("All sequences")
    for i in range(len(seq)):
        print("set %d = " %(i+1), end="")
        print(seq[i])

 example output:
 what is height of tree?3

       ___12      
      /     \     
  __ 6       13   
 /   \        \  
 0     11       14
  \               
   2              


  All sequences
  set 1 = [12, 6, 0, 2, 11, 13, 14]
  set 2 = [12, 6, 0, 2, 13, 11, 14]
  set 3 = [12, 6, 0, 2, 13, 14, 11]
  set 4 = [12, 6, 0, 13, 2, 11, 14]
  set 5 = [12, 6, 0, 13, 2, 14, 11]
  set 6 = [12, 6, 0, 13, 14, 2, 11]
  set 7 = [12, 6, 13, 0, 2, 11, 14]
  set 8 = [12, 6, 13, 0, 2, 14, 11]
  set 9 = [12, 6, 13, 0, 14, 2, 11]
  set 10 = [12, 6, 13, 14, 0, 2, 11]
  set 11 = [12, 13, 6, 0, 2, 11, 14]
  set 12 = [12, 13, 6, 0, 2, 14, 11]
  set 13 = [12, 13, 6, 0, 14, 2, 11]
  set 14 = [12, 13, 6, 14, 0, 2, 11]
  set 15 = [12, 13, 14, 6, 0, 2, 11]
  set 16 = [12, 6, 0, 11, 2, 13, 14]
  set 17 = [12, 6, 0, 11, 13, 2, 14]
  set 18 = [12, 6, 0, 11, 13, 14, 2]
  set 19 = [12, 6, 0, 13, 11, 2, 14]
  set 20 = [12, 6, 0, 13, 11, 14, 2]
  set 21 = [12, 6, 0, 13, 14, 11, 2]
  set 22 = [12, 6, 13, 0, 11, 2, 14]
  set 23 = [12, 6, 13, 0, 11, 14, 2]
  set 24 = [12, 6, 13, 0, 14, 11, 2]
  set 25 = [12, 6, 13, 14, 0, 11, 2]
  set 26 = [12, 13, 6, 0, 11, 2, 14]
  set 27 = [12, 13, 6, 0, 11, 14, 2]
  set 28 = [12, 13, 6, 0, 14, 11, 2]
  set 29 = [12, 13, 6, 14, 0, 11, 2]
  set 30 = [12, 13, 14, 6, 0, 11, 2]
  set 31 = [12, 6, 11, 0, 2, 13, 14]
  set 32 = [12, 6, 11, 0, 13, 2, 14]
  set 33 = [12, 6, 11, 0, 13, 14, 2]
  set 34 = [12, 6, 11, 13, 0, 2, 14]
  set 35 = [12, 6, 11, 13, 0, 14, 2]
  set 36 = [12, 6, 11, 13, 14, 0, 2]
  set 37 = [12, 6, 13, 11, 0, 2, 14]
  set 38 = [12, 6, 13, 11, 0, 14, 2]
  set 39 = [12, 6, 13, 11, 14, 0, 2]
  set 40 = [12, 6, 13, 14, 11, 0, 2]
  set 41 = [12, 13, 6, 11, 0, 2, 14]
  set 42 = [12, 13, 6, 11, 0, 14, 2]
  set 43 = [12, 13, 6, 11, 14, 0, 2]
  set 44 = [12, 13, 6, 14, 11, 0, 2]
  set 45 = [12, 13, 14, 6, 11, 0, 2]

答案 3 :(得分:0)

这是另一个基于递归的简洁易懂的解决方案:

from binarytree import  Node, bst, pprint

def allsequences1(root):
    if not root:
        return None
    lt = allsequences1(root.left)
    rt = allsequences1(root.right)
    ret = []
    if not lt and not rt:
        ret.append([root])
    elif not rt:
        for one in lt:
            ret.append([root]+one)
    elif not lt:
        for two in rt:
            ret.append([root]+two)
    else:
        for one in lt:
            for two in rt:
                ret.append([root]+one+two)
                ret.append([root]+two+one)
    return ret



if __name__=="__main__":
    n = int(input("what is height of tree?"))
    my_bst = bst(n)
    pprint(my_bst)
    seg = allsequences1(my_bst)
    print("All sequences ..1")
    for i in range(len(seq)):
        print("set %d = " %(i+1), end="")
        print(seq[i])

答案 4 :(得分:0)

请注意,问题实际上是关于一棵树的topological sorting:找到执行拓扑排序的所有可能方法。也就是说,我们不在乎树的具体构建方式,重要的是元素总是作为叶子添加,而不会更改现有节点的结构。输出的限制是节点永远不会在其祖先之前-将树视为经典dependency graph

但是与一般DAG的拓扑排序不同,这里不需要引用计数,因为这是一棵树-引用数始终为1或0。

这是一个简单的Python实现:

def all_toposorts_tree(sources, history):
    if not sources:
        print(history)
        return
    for t in sources:
        all_toposorts((sources - {t}) | {t.left, t.right} - {None}, history + [t.v])

all_toposorts_tree({root}, [])

这是Cracking the Coding Interview, 6th Edition中的问题4.9。

答案 5 :(得分:0)

让我们首先观察创建相同的BST必须遵循的内容。这里唯一足够的规则是在其左,右子级之前插入父级。因为,如果我们可以保证为某个节点(我们要插入)插入了所有父节点(包括祖父节点),但没有插入任何子节点,则该节点将找到要插入的适当位置。

根据此观察,我们可以回溯以生成将产生相同BST的所有序列。

active_list = {root}
current_order = {}
result ={{}}
backtrack():
     if(len(current_order) == total_node):
         result.push(current_order)
         return;
     for(node in active_list):
          current_order.push(node.value)

          if node.left : 
               active_list.push(node.left)
          if node.right: 
               active_list.push(node.right)

          active_list.remove(node)
          backtrack()
          active_list.push(node)

          if node.left : 
               active_list.remove(node.left)
          if node.right: 
               active_list.remove(node.right)
          current_order.remove(node.val)

这不起作用。仅用于说明目的。

答案 6 :(得分:0)


public class Solution {
    ArrayList<LinkedList<Long>> result;
    /*Return the children of a node */
    ArrayList<TreeNode> getChilden(TreeNode parent) {
        ArrayList<TreeNode> child = new ArrayList<TreeNode>();
        if(parent.left != null) child.add(parent.left);
        if(parent.right != null) child.add(parent.right);
        return child;
    }
    /*Gets all the possible Compinations*/
    void getPermutations(ArrayList<TreeNode> permutations, LinkedList<Long> current) {
        if(permutations.size() == 0) {
            result.add(current);
            return;
        }
        int length = permutations.size();
        for(int i = 0; i < length; i++) {
            TreeNode node = permutations.get(i);
            permutations.remove(i);
            ArrayList<TreeNode> newPossibilities = new ArrayList<TreeNode>();
            newPossibilities.addAll(permutations);
            newPossibilities.addAll(getChilden(node));
            LinkedList<Long> newCur = new LinkedList<Long>();
            newCur.addAll(current);
            newCur.add(node.val);
            getPermutations(newPossibilities, newCur);
            permutations.add(i,node);
        }
    }

    /*This method returns a array of arrays which will lead to a given BST*/
    ArrayList<LinkedList<Long>> inputSequencesForBst(TreeNode node) { 
        result = new ArrayList<LinkedList<Long>>();
        if(node == null)
            return result;
        ArrayList<TreeNode> permutations = getChilden(node);
        LinkedList<Long> current = new LinkedList<Long>();
        current.add(node.val);
        getPermutations(permutations, current);
        return result;
    }
}

我的解决方案。完美运作。

答案 7 :(得分:0)

我的解决方案要短得多。您如何看待?

OffsetAttribute = jpype.JClass('org.apache.lucene.analysis.tokenattributes.OffsetAttribute')

答案 8 :(得分:0)

这是我的 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