Перечисление всех путей в дереве - PullRequest
7 голосов
/ 15 апреля 2011

Мне было интересно, как лучше всего реализовать древовидную структуру данных, чтобы можно было перечислять пути всех уровней. Позвольте мне объяснить это на следующем примере:

     A
   /   \
   B    C
   |    /\
   D   E  F

Я хочу иметь возможность генерировать следующее:

A
B
C
D
E
F
A-B
A-C
B-D
C-E
C-F
A-B-D
A-C-E
A-C-F

На данный момент я выполняю поиск в глубину для различных глубин в структуре данных, построенной с использованием словаря, и записываю уникальные узлы, которые были замечены, но мне было интересно, есть ли лучший способ сделать такой вид ВТП. Есть предложения?

Ответы [ 3 ]

7 голосов
/ 15 апреля 2011

Всякий раз, когда вы обнаружите проблему на деревьях, просто используйте рекурсию: D

def paths(tree):
  #Helper function
  #receives a tree and 
  #returns all paths that have this node as root and all other paths

  if tree is the empty tree:
    return ([], [])
  else: #tree is a node
    root = tree.value
    rooted_paths = [[root]]
    unrooted_paths = []
    for subtree in tree.children:
        (useable, unueseable) = paths(subtree)
        for path in useable:
            unrooted_paths.append(path)
            rooted_paths.append([root]+path)
        for path in unuseable:
            unrooted_paths.append(path)
    return (rooted_paths, unrooted_paths)

def the_function_you_use_in_the_end(tree):
   a,b = paths(tree)
   return a+b
0 голосов
/ 31 июля 2012

Еще один способ:

Каждый путь без повторений в дереве однозначно описывается его началом и концом.

Таким образом, один из способов перечисления путей - это перечисление всех возможных пар вершин.,Для каждой пары относительно легко найти путь (найти общего предка и пройти по нему).

0 голосов
/ 15 апреля 2011

Найдите путь к каждому узлу дерева с помощью поиска в глубину, а затем вызовите enumerate-paths(Path p), где p - путь от корня к узлу. Предположим, что путь p - это массив узлов p[0] [1] .. p[n], где p[0] - корень, а p[n] - текущий узел.

enumerate-paths(p) {
    for i = 0 .. n  
        output p[n - i] .. p[n] as a path. 
}

Каждый из этих путей отличается, и каждый из них отличается от результатов, возвращаемых любым другим узлом дерева, поскольку никакие другие пути не заканчиваются на p[n]. Ясно, что это завершено, так как любой путь от узла к некоторому узлу между ним и корнем. Он также является оптимальным, поскольку он находит и выводит каждый путь ровно один раз.

Порядок будет немного отличаться от вашего, но вы всегда можете создать массив списков путей, где A[x] - это список путей длиной x. Затем вы можете вывести пути в порядке их длины, хотя для этого потребуется O (n) памяти.

...