简体   繁体   English

如何从预排序树遍历产生的数组中重建二叉树

[英]How to reconstrunct a binary tree from an array produced by preorder tree traversal

I was asked to implement a preorder tree traversal function, that function should have returned an array representing the tree, and then I was asked to implement a function to reconstruct the tree from the array my previous function returned. 我被要求实现一个预排序树遍历函数,该函数应该返回一个表示树的数组,然后我被要求实现一个函数以从我先前返回的数组中重构树。 Something like sending a binary tree from one pc and then receiving and reconstructing it on the receiving end. 类似于从一台pc发送一棵二叉树,然后在接收端进行接收和重构。 The important part is that the data should only be transferred once, so I couldn't use the standard preorder and inorder combination. 重要的部分是数据只能传输一次,所以我不能使用标准的预购和订购组合。

In my solution, each node is printed, and then added to an array that contains all of the printed nodes, if a node doesn't have a left subtree it will print and add the letter "L", and if the tree doesn't have a right subtree it will print and add the letter "R" to the array. 在我的解决方案中,将打印每个节点,然后将其添加到包含所有已打印节点的数组中,如果一个节点没有左子树,它将打印并添加字母“ L”,并且如果树没有t有一个正确的子树,它将打印并将字母“ R”添加到数组中。

That part was easy, however, I didn't know how to reconstruct the tree on the receiving side. 那部分很简单,但是,我不知道如何在接收端重建树。 Any help or idea will be really appreciated. 任何帮助或想法将不胜感激。

Here is what I have done for the sending part: 这是我对发送部分所做的操作:

class TreeNode(object):
"""This class represents a tree."""

    def __init__(self, data, left=None, right=None):
        self.data = data
        self.left = left
        self.right = right

def send(arr_tree, data):
    print(data)
    arr_tree.append(data)

def send_sub_tree(arr_tree, node):
    send(arr_tree, node.data)
    if node.left is None:
        send(arr_tree, "L")
    else:
        send_sub_tree(arr_tree, node.left)
    if node.right is None:
        send(arr_tree, "R")
    else:
        send_sub_tree(arr_tree, node.right)

if __name__ == '__main__':
    tree = TreeNode(1, TreeNode(2, TreeNode(4), TreeNode(5)), TreeNode(3, 
    TreeNode(6), TreeNode(7)))
    received_tree = []
    send_sub_tree(received_tree, tree)
    reconstructed_tree = reconstruct_tree(received_tree)

EDIT: 编辑:

I have managed to implement something that kind-of works, but its messy and doesn't reconstruct the sent part perfectly: 我设法实现了某种可行的功能,但是它很凌乱并且不能完美地重构发送的部分:

def reconstruct_tree(arr_tree):
    node = TreeNode(arr_tree[0])
    print(node.data)

    if arr_tree[1] == "L" and arr_tree[2] == "R":
        if len(arr_tree) > 3 and arr_tree[3] != "L" and arr_tree[3] != "R":
            node.right = reconstruct_tree(arr_tree[3:])

    else:
        return node
    if arr_tree[1] != "L":
        node.left = reconstruct_tree(arr_tree[1:])
        return node

return node

Here is how you could do it. 这是您的方法。 I have also moved your functions inside the class, renamed them, and made some modifications: 我也将您的函数移到了类中,并将其重命名并进行了一些修改:

class TreeNode(object):
    """This class represents a tree."""
    def __init__(self, data, left=None, right=None):
        self.data = data
        self.left = left
        self.right = right

    def to_list(self):
        return [self.data] + (
                self.left.to_list() if self.left else ["L"]
            ) + (
                self.right.to_list() if self.right else ["R"]
            )

    @staticmethod
    def from_list(lst):
        def recurse(it):
            try:
                data = next(it)
            except StopIteration: # Only happens if list is incomplete
                return
            if data == 'L' or data == 'R':
                return
            return TreeNode(data, recurse(it), recurse(it))
        return recurse(iter(lst))

tree = TreeNode(1, 
            TreeNode(2, 
                TreeNode(4),
                TreeNode(5)
            ), 
            TreeNode(3, 
                TreeNode(6),
                TreeNode(7)
            )
        )
lst = tree.to_list()
print(lst)
# Reverse operation
recovered_tree = TreeNode.from_list(lst)
# Make that a list again to see if it is the same tree
lst2 = recovered_tree.to_list()
print(lst2) # Same as lst

See it run on repl.it 看到它在repl.it上运行

Note that you could use "L" for the right-side child as well, or "R" for the left one, as the position in the array already leaves no doubt about which child is intended. 请注意,您也可以对右侧的孩子使用“ L”,也可以对左侧的孩子使用“ R”,因为数组中的位置已经毫无疑问地意味着要使用哪个孩子。 One special symbol is enough. 一个特殊的符号就足够了。

Let's think about a general algorithm, using Wikipedia's example of pre-order traversal: 让我们考虑一个通用算法,使用Wikipedia的示例遍历示例:

从Wikipedia进行遍历

F, B, A, D, C, E, G, I, H.

Let's mark a None for a null subtree: 让我们为空子树标记一个None

A = [F, B, A, None, None, D, C, None, None, E, None, None, G, None, I, H, None]

Now we start at the root: 现在我们从根开始:

F
-> have a left subtree so insert B
   descend
-> have a left subtree so insert A
   descend
-> have no left subtree
-> have no right subtree
   return
-> have a right subtree so insert D
   descend
-> have a left subtree so insert C
   descend
-> have no left subtree
-> have no right subtree
   return
-> have a right subtree so insert E
   descend
-> have no left subtree
-> have no right subtree
   return

But how do we know which index and node we return to? 但是我们如何知道返回哪个索引和节点呢? One way is to call a recursive function from the node that returns the next index to use (remember here and in the example that follows that i is a local variable): 一种方法是从返回下一个要使用的索引的节点调用递归函数(请记住,在下面的示例中, i是局部变量):

f(node, i):
  # left subtree
  if A[i]:
    insertLeft(A[i])
    i = f(node.left, i + 1)
  else:
    i = i + 1

  #right subtree
  if A[i]:
    insertRight(A[i])
    i = f(node.right, i + 1)
  else
    i = i + 1

  return i

Let's apply to our example: 让我们将其应用于示例:

A = [F, B, A, None, None, D, C, None, None, E, None, None, G, None, I, H, None]

f(F, 1)
  insertLeft(B)

  i = f(B,2)
        insertLeft(A)

        i = f(A,3)
              i = 4
              i = 5
              return 5

        insertRight(D)

        i = f(D,6)
              insertLeft(C)

              i = f(C,7)
                    i = 8
                    i = 9
                    return 9

              insertRight(E)

              i = f(C,10)
                    i = 11
                    i = 12
                    return 12

              return 12

        return 12

  insertRight(G)  # A[12]

  etc...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM