簡體   English   中英

在Python中遍歷一個不尋常的樹

[英]Traversing an unusual tree in Python

我有一個像這樣的不尋常的樹數組:

[[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] - 0 is followed by 1
[1, 2] - 1 is followed by 2

我試圖提取這樣的數組:

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

我無法編寫強大的遍歷來提取所有可能的路徑。 我怎么能用Python做到這一點?

你可以使用遞歸生成器函數來完成它。 我假設樹中的根節點始終位於原始列表中的所有子節點之前。

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

輸出:

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

說明:首先,我構建一個包含每個節點的所有可能路徑的列表。 然后,對於我尚未使用的每個節點,我假設它是一個根節點,並遞歸地查找從哪個路徑引出。 如果沒有從任何節點找到路徑,它就是一個葉子節點,我停止遞歸並返回找到的路徑。

如果關於節點順序的假設不成立,那么首先必須找到所有根節點的集合。 這可以通過查找在任何連接中不顯示為第二個節點的所有節點來完成。

根據我對您的問題的理解,看起來您有一組父子關系作為描述的對列表。 你似乎遇到麻煩,認為它有一個像鏈表一樣的結構。 與鏈表不同,樹是更通用的形式,它可以具有多個節點,這些節點“跟隨”被稱為其子節點的給定節點。

最簡單的方法是首先簡單地構建樹,然后從根遍歷它。 定義一個具有兩個字段的Node類,一個用於節點的值,另一個用於子節點列表。 然后迭代列表中的項目,將每對的第二個元素添加到與該對的第一個元素對應的節點的子列表中。 構建樹之后,使用遞歸打印函數打印當前節點並在其子節點上調用它自己(如果有的話)。 在根節點上調用該函數應該打印整個樹。

我會發布一些代碼,但這看起來很像家庭作業。 上面的解釋應該足以開始。

我能想到的最簡單的方法是構造一個包含給定父級的所有可能子級的字典,如下所示:

d = {}

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

樹= [[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]}

現在可以像這樣以遞歸方式遍歷樹:

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])

我沒有測試過遞歸,但它應該給你一個想法:)

干得好。 不是地球上最好的代碼,但它有效:

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

看看這個問題,似乎最好的方法可能是在幾次迭代中向后構建數組。 我的想法是這樣的,但請注意我們必須假設這是一棵樹,所以葉子只能使用一次:

  1. 讓數組=對的列表
  2. 直到數組中的每個數組都是葉子:
    1. 如果數組是葉子(最后一個元素不是數組中任何數組中的第一個元素):
      1. 對於數組中的每個數組,查看葉子是否可以附加到它的末尾
      2. 附加到所有可能的數組后,刪除葉子

顯然你必須做一些工作才能把它變成代碼,但這是一個粗略的想法。

您可以使用以下頁面中的find_all_paths函數: http ://www.python.org/doc/essays/graphs/

為了使用它,您需要對圖表進行兩次小調整。 首先,循環遍歷邊緣列表並創建圖形的新表示,如:

    graph = {0: [1, 7],
             1: [2],
             2: [3, 4, 5],
             ...}
其次創建一個超級鏈接(在您的示例中,您可以將其稱為10)並將所有頂點附加到沒有邊緣的頂點到此新節點。

然后,您可以調用函數find_all_paths(graph, 0, 10)來查找所有這些路徑。

從所有可能的起始節點生成所有最長的路徑:

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

如果它只應該生成不屬於從其他節點開始的不同的更長路徑的路徑,則需要將parts初始化為未包含在[p[1] for p in tree]所有節點。 如果你想要所有路徑而不是最長路徑,那么在while循環的每次迭代中都應該有一個打印。

以下工作 - 從root開始生成樹。 根被認為是沒有父節點的節點。

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