从两个平面表示重新创建一棵树

时间:2011-04-07 14:25:54

标签: algorithm tree graph-algorithm

我有一个树的两个平面表示,例如:

List 1:        List 2:

Event1      Event1
Event1      State1
Event2      Event1
State1      Event2
Event2      Event2
Event1      State2
Event2      StateI1
StateI1     Event1
Event1      Event2
Event1      Event1
Event2      StateI2
StateI2     Event1
Event2      Event2
Event1      Event2
Event2      StateI3
StateI3     Event1
State2      Event2
Event3      Event3

树是:

Event1 
State1
  Event1 
  Event2 
Event2 
State2
  StateI1
    Event1 
    Event2 
  Event1 
  StateI2
    Event1 
    Event2 
  Event2 
  StateI3
    Event1 
    Event2 
Event3

如您所见,一个国家可以拥有多个事件和国家。不要介意名称,它们不相关,它们只是表示元素的类型。

我相信第一个列表是树的深度优先,自下而上的遍历,第二个列表是深度优先,自上而下的遍历。

我需要从两个平面列表中重新创建树,即将每个State或Event分配给其父状态(或顶层)。这可能吗?如果是这样,怎么样?

我的代码中基本上发生的是:

TraverseTreeBottomUpExecutingFunction(tree, &myfunc_bottomup)

second_list = TraverseTreeTopDown(tree)

recreated_tree = myfunc_recreate_tree(second_list, optional_first_list_created_using_myfunc_bottomup)

我无法更改Traverse *功能。

1 个答案:

答案 0 :(得分:2)

基本上不是二叉树的树可以按两个顺序遍历:preorder(在挂起的子树之前枚举内部节点)和postorder(在挂起的子树之后枚举内部节点)。我猜你的问题是“自下而上”是后序,“自上而下”是预购。

让我们进一步假设所有对象可以彼此分离,即它们具有不同的值或指针。如果所有对象都是相同的,即所有对象都是相同的状态,则不能仅从遍历列表中推断出树的形状,因为它们看起来完全相同。

现在的问题是,如果有一个树T,并且预订序和后序遍历为它生成了节点列表,那么该树的ROOT是预订单列表中的FIRST节点和后序列表上的LAST节点。这为您提供了以下重建方法:

您有两个列表,preorder和postorder遍历的节点列表。称这些为R(pRe)和O(pOst)。

  • R的第一个元素是根节点。从R
  • 中删除它
  • 从O中删除最后一个元素并检查它是否是相同的根节点(应该是)
  • 现在检查R的第一个元素,它是最左边子树的根
  • 从O中找到相同的节点;让我们说它是O
  • 上的 k 节点
  • 现在最左边的子树上有 k 个节点;从列表R和O中取出第一个 k 节点,然后递归执行此算法以重建最左边的子树
  • 继续使用R和O的剩余部分,重复此操作,以重建根节点的剩余子树

伪代码 - 返回树的递归过程。输入:两个遍历列表r = preorder,o = postorder

def mktree(r, o):
  l = len(r)
  assert l == len(o)
  root = r[0]
  assert root == o[l - 1]
  if l == 1:
     return mknode(root)
  else:
     myroot = mknode(root)
     r = r[1:l]     # sublist that excludes first element 
     o = o[0:l-1]   # sublist that excludes last element
     while len(r) > 0: # iterate and construct subtrees
       first = r[0]
       lim = -1
       for i in 0..l - 1:
         if o[i] == first:
            lim = i + 1
            break
       assert lim != -1
       myroot.add_rightmost_child(mktree(r[0:lim], o[0:lim])
       r = r[lim:len(r)] # sublist from lim until end of list
       o = o[lim:len(o)] # sublist from lim until end of list
     return myroot

以下是其工作原理的示例:

原树:

            1
          / | \
         2  3  4
        /     / \
       5      6  7

预订遍历(“自上而下深度优先”):1 2 5 3 4 6 7

后序遍历(“自下而上”):5 2 3 6 7 4 1

算法执行:

mktree(1253467, 5236741)
    myroot = 1
    r = 253467, o = 523674
    loc = 1 (location of '2' in o)
         mktree(25, 52)
              myroot = 2
              mktree(5, 5) -> returns singleton tree 5
         list exhausted -> returns tree 2[5] (5 only child of 2)
    add 2[5] to myroot as right child, tree at myroot 1[2[5]]
    r = 3467, o = 3674 (stripped away "25" that was processed)
    loc = 0 (location of '3' in o)
         mktree(3, 3) returns singleton tree 3
    add 3 to myroot as right child, tree at myroot 1[2[5], 3]
    r = 467, o = 674 (stripped away "3" that was processed)
    loc = 2 (location of '4' in o)
         mktree(467, 674)
              myroot = 4
              r = 67, o = 67
              (recursive calls return first singleton 6, then 7)
              returns tree 4[6,7]
    add 4[6,7] to myroot as right child, tree at myroot 1[2[5],3,4[6,7]]
    list exhausted, return tree

结果,重建了原始树。

作为参考,这里定义了伪代码中的前序和后序遍历:

 def preorder(t):
     l = [root_node(t)]     # BEFORE recursion = PREorder
     for c in t.children(): # in left to right order
         l.append(preorder(c))
     return l

 def postorder(t):
     l = []
     for c in t.children(): # in left to right order
         l.append(postorder(c))
     l.append(root_node(t)) # AFTER recursion = POSTorder
     return l