简体   繁体   English

在Python中遍历一个不寻常的树

[英]Traversing an unusual tree in Python

I have an unusual tree array like this: 我有一个像这样的不寻常的树数组:

[[0, 1], [1, 2], [2, 3], [2, 4], [2, 5], [5, 6], 
 [4, 6], [3, 6], [0, 7], [7, 6], [8, 9], [9, 6]]

Each element of the array is a pair, which means second one is a follower of the first, eg: 数组的每个元素都是一对,这意味着第二个元素是第一个元素的跟随者,例如:

[0, 1] - 0 is followed by 1
[1, 2] - 1 is followed by 2

I am trying to extract array like this: 我试图提取这样的数组:

0 1 2 3 6    
0 1 2 4 6    
0 1 2 5 6
0 7 6
8 9 6

I couldn't code a robust traversal to extract all possible paths like this. 我无法编写强大的遍历来提取所有可能的路径。 How can I do it with Python? 我怎么能用Python做到这一点?

You could do it using a recursive generator function. 你可以使用递归生成器函数来完成它。 I assume that the root node in the tree always comes before all its children in the original list. 我假设树中的根节点始终位于原始列表中的所有子节点之前。

tree = [[0, 1], [1, 2], [2, 3], [2, 4], [2, 5], [5, 6], [4, 6], [3, 6],
        [0, 7], [7, 6], [8, 9], [9, 6]]

paths = {}
for t in tree:
    if t[0] not in paths: paths[t[0]] = []
    paths[t[0]].append(tuple(t))

used = set()

def get_paths(node):
    if node[1] in paths:
        for next_node in paths[node[1]]:
            used.add(next_node)
            for path in get_paths(next_node):
                yield [node[0]] + path
    else:
        yield [node[0], node[1]]

for node in tree:
    if tuple(node) in used: continue
    for path in get_paths(node):
        print path

Output: 输出:

[0, 1, 2, 3, 6]
[0, 1, 2, 4, 6]
[0, 1, 2, 5, 6]
[0, 7, 6]
[8, 9, 6]

Explanation: First I construct a list of all possible paths from each node. 说明:首先,我构建一个包含每个节点的所有可能路径的列表。 Then for each node that I haven't used yet I assume it is a root node and recursively find which paths lead from it. 然后,对于我尚未使用的每个节点,我假设它是一个根节点,并递归地查找从哪个路径引出。 If no paths are found from any node, it is a leaf node and I stop the recursion and return the path found. 如果没有从任何节点找到路径,它就是一个叶子节点,我停止递归并返回找到的路径。

If the assumption about the order of the nodes does not hold then you would first have to find the set of all root nodes. 如果关于节点顺序的假设不成立,那么首先必须找到所有根节点的集合。 This can be done by finding all nodes that do not appear as the second node in any connection. 这可以通过查找在任何连接中不显示为第二个节点的所有节点来完成。

From what I understand of your question, it looks like you have a set of parent-child relationships as a list of pairs that describes a tree . 根据我对您的问题的理解,看起来您有一组父子关系作为描述的对列表。 You seem to be running into trouble by thinking that it has a structure like a linked list. 你似乎遇到麻烦,认为它有一个像链表一样的结构。 Unlike a linked list, a tree is a more general form, it can have multiple nodes that 'follow' a given node that are called its children. 与链表不同,树是更通用的形式,它可以具有多个节点,这些节点“跟随”被称为其子节点的给定节点。

The easiest way is to simply build the tree first and then traverse it from the root. 最简单的方法是首先简单地构建树,然后从根遍历它。 Define a Node class that has two fields, one for the value of the node and the other a list of children. 定义一个具有两个字段的Node类,一个用于节点的值,另一个用于子节点列表。 Then you iterate over the items of your list adding the second element of each pair to the children list of node corresponding to the first element of the pair. 然后迭代列表中的项目,将每对的第二个元素添加到与该对的第一个元素对应的节点的子列表中。 After the tree is built, you use a recursive print function that prints the current node and calls itself on its children (if there are any). 构建树之后,使用递归打印函数打印当前节点并在其子节点上调用它自己(如果有的话)。 Calling the function on the root node should print the whole tree. 在根节点上调用该函数应该打印整个树。

I would post some code, but this looks a lot like homework. 我会发布一些代码,但这看起来很像家庭作业。 The above explanation should be enough for a start. 上面的解释应该足以开始。

The easiest way I can think of, would be to construct a dictionary that contains all possible children for a given parent, like so: 我能想到的最简单的方法是构造一个包含给定父级的所有可能子级的字典,如下所示:

d = {}

for parent, child in tree:
    try:
        d[parent].append(child)
    except KeyError:
        d[parent] = [child]

with tree = [[0, 1], [1, 2], [2, 3], [2, 4], [2, 5], [5, 6], [4, 6], [3, 6], [0, 7], [7, 6], [8, 9], [9, 6]], this would produce: 树= [[0,1],[1,2],[2,3],[2,4],[2,5],[5,6],[4,6],[3,6] ],[0,7],[7,6],[8,9],[9,6]],这会产生:

{0: [1, 7],
 1: [2],
 2: [3, 4, 5],
 3: [6],
 4: [6],
 5: [6],
 7: [6],
 8: [9],
 9: [6]}

Now it's possible to recursively traverse the tree like this: 现在可以像这样以递归方式遍历树:

def printPaths(d, currentPath):
    if currentPath[-1] not in d:
        print currentPath # last node can't possibly be a parent, so stop
    else:
        for child in d[currentPath[-1]]:
            printPaths(d, currentPath + [child])


for root in d:
    printPaths(d, [root])

I haven't tested the recursion, but it should give you an idea :) 我没有测试过递归,但它应该给你一个想法:)

Here you go. 干得好。 Not the nicest code on earth but it works: 不是地球上最好的代码,但它有效:

inputValues = [[0, 1], [1, 2], [2, 3], [2, 4], [2, 5], [5, 6], [4, 6], [3, 6], [0, 7], [7, 6], [8, 9], [9, 6]]

tree = {}
numberOfChildren = {}
for (f, t) in inputValues:
  if not tree.has_key(f):
    tree[f] = []
  tree[f].append(t)
  if not numberOfChildren.has_key(t):
    numberOfChildren[t] = 0
  numberOfChildren[t] += 1

roots = [c for c in tree if c not in numberOfChildren]
permutations = []

def findPermutations(node, currentList):
  global tree
  global permutations
  if not tree.has_key(node):
    permutations.append(currentList)
    return
  for child in tree[node]:
    l = list()
    l.extend(currentList)
    l.append(child)
    findPermutations(child, l)

for r in roots:
  findPermutations(r, [r])

print permutations

Looking at the problem, it seems the best approach might be to build the arrays backwards over several iterations. 看看这个问题,似乎最好的方法可能是在几次迭代中向后构建数组。 My idea is this, but note we have to assume that this is a tree and so the leaves can only be used once: 我的想法是这样的,但请注意我们必须假设这是一棵树,所以叶子只能使用一次:

  1. Let arrays = list of pairs 让数组=对的列表
  2. Until every array in arrays are leaf: 直到数组中的每个数组都是叶子:
    1. If an array is a leaf (last element isn't the first element in any array in arrays): 如果数组是叶子(最后一个元素不是数组中任何数组中的第一个元素):
      1. For each array in arrays see if the leaf can be attached on to the end of it 对于数组中的每个数组,查看叶子是否可以附加到它的末尾
      2. After attaching to all possible arrays, delete the leaf 附加到所有可能的数组后,删除叶子

Obviously you'll have to do some work to turn that into code, but that's a rough idea. 显然你必须做一些工作才能把它变成代码,但这是一个粗略的想法。

You could use the find_all_paths function from the following page: http://www.python.org/doc/essays/graphs/ 您可以使用以下页面中的find_all_paths函数: http ://www.python.org/doc/essays/graphs/

In order to use this you need to make two minor tweeks to your graph. 为了使用它,您需要对图表进行两次小调整。 First, loop through your list of edges and create a new representation of the graph like: 首先,循环遍历边缘列表并创建图形的新表示,如:

    graph = {0: [1, 7],
             1: [2],
             2: [3, 4, 5],
             ...}
Secondly create a supersink (in your example case you could call it 10) and attach all vertices with no edges leading from them to this new node. 其次创建一个超级链接(在您的示例中,您可以将其称为10)并将所有顶点附加到没有边缘的顶点到此新节点。

Then you can call the function find_all_paths(graph, 0, 10) to find all such paths. 然后,您可以调用函数find_all_paths(graph, 0, 10)来查找所有这些路径。

Produce all longest pathes from all possible starting nodes: 从所有可能的起始节点生成所有最长的路径:

tree = [[0, 1], [1, 2], [2, 3], ...]

dtree = {}
for (k, v) in tree:
   dtree.setdefault(k, []).append(v)

parts = [[root] for root in range(10)]

while parts:
   path = parts.pop(0)
   if path[-1] in dtree:
      for n in dtree[path[-1]]:
         parts.append(path + [n])
   else:
      print path

If it should only produce paths that are not part of a different, longer path starting at some other node, parts would need to be initialized to all nodes not contained in [p[1] for p in tree] . 如果它只应该生成不属于从其他节点开始的不同的更长路径的路径,则需要将parts初始化为未包含在[p[1] for p in tree]所有节点。 And if you want all paths instead, not just the longest ones, there should be a print in every iteration of the while-loop. 如果你想要所有路径而不是最长路径,那么在while循环的每次迭代中都应该有一个打印。

The following works - generate the trees starting from root. 以下工作 - 从root开始生成树。 The roots are considered the nodes that do not have a parent. 根被认为是没有父节点的节点。

import operator
def genpaths(data):
    # Initialize dictionary
    ddata = {}
    for item in data:
        ddata.setdefault(item[0], []).append(item[1])
    def genpath(root):
        "Generate paths starting with root"
        if root not in ddata:
            yield (root, )
        else:
            for child in ddata[root]:
                for path in genpath(child):
                    yield (root, ) + path

    for root in set(ddata.keys()) - set(reduce(operator.add, ddata.values())):
        for path in genpath(root):
            print path

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

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