Как я могу реализовать дерево в Python?

Ответы:

233

anytree

Я рекомендую https://pypi.python.org/pypi/anytree (я автор)

пример

from anytree import Node, RenderTree

udo = Node("Udo")
marc = Node("Marc", parent=udo)
lian = Node("Lian", parent=marc)
dan = Node("Dan", parent=udo)
jet = Node("Jet", parent=dan)
jan = Node("Jan", parent=dan)
joe = Node("Joe", parent=dan)

print(udo)
Node('/Udo')
print(joe)
Node('/Udo/Dan/Joe')

for pre, fill, node in RenderTree(udo):
    print("%s%s" % (pre, node.name))
Udo
├── Marc
   └── Lian
└── Dan
    ├── Jet
    ├── Jan
    └── Joe

print(dan.children)
(Node('/Udo/Dan/Jet'), Node('/Udo/Dan/Jan'), Node('/Udo/Dan/Joe'))

Характеристики

У anytree также есть мощный API с:

  • простое создание дерева
  • простая модификация дерева
  • предварительный заказ дерева итерации
  • повторение дерева после заказа
  • разрешить относительные и абсолютные пути к узлам
  • ходьба от одного узла к другому.
  • рендеринг дерева (см. пример выше)
  • присоединение / отсоединение узлов
c0fec0de
источник
31
Просто лучший ответ, другие изобретают велосипед.
Ондрей
66
Это хорошая форма, чтобы сообщить, что вы являетесь автором пакета, который вы рекомендуете в своем ответе.
Джон Y
3
@ c0fec0de Я люблю тебя !!!! Эта библиотека удивительна, даже имеет функцию визуализации
layser
2
@Ondrej хорошо, другие ответы меньше зависимостей, и оригинальный вопрос действительно задавал о встроенных структурах данных. Хотя anytreeэто, вероятно, отличная библиотека, это вопрос Python, а не вопрос Node.js.
Роб Роуз,
Я наткнулся на этот ответ через Google. Эта библиотека действительно хороша. Мне особенно нравится возможность использовать класс mixin для создания дерева любого объекта!
Rÿck Nöthing
104

Python не обладает таким обширным диапазоном «встроенных» структур данных, как в Java. Однако, поскольку Python является динамическим, общее дерево легко создать. Например, двоичное дерево может быть:

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

Вы можете использовать это так:

root = Tree()
root.data = "root"
root.left = Tree()
root.left.data = "left"
root.right = Tree()
root.right.data = "right"
Грег Хьюгилл
источник
109
Это не очень объясняет создание полезной древовидной реализации.
Майк Грэм,
14
Вопрос помечен Python3, тогда нет необходимости извлекать его class Treeиз объекта
cfi
3
@cfi Получение из objectиногда является лишь руководством: если класс наследует от других базовых классов, явно наследовать от объекта. Это также относится к вложенным классам. См. Руководство по стилю Google Python
Конрад Райх,
16
@platzhirsch: Пожалуйста, прочитайте и процитируйте руководство полностью: Google явно указывает, что это необходимо для работы кода Python 2, и рекомендует улучшить совместимость с Py3. Здесь мы говорим о коде Py3. Там нет необходимости делать дополнительную, традиционную печать.
Cfi
13
Это двоичное дерево, а не общее, как просили.
Майкл Дорнер
49

Родовое дерево - это узел с нулем или более дочерних узлов, каждый из которых является собственным (древовидным) узлом. Это не то же самое, что бинарное дерево, это разные структуры данных, хотя обе имеют общую терминологию.

В Python нет встроенной структуры данных для универсальных деревьев, но ее легко реализовать с помощью классов.

class Tree(object):
    "Generic tree node."
    def __init__(self, name='root', children=None):
        self.name = name
        self.children = []
        if children is not None:
            for child in children:
                self.add_child(child)
    def __repr__(self):
        return self.name
    def add_child(self, node):
        assert isinstance(node, Tree)
        self.children.append(node)
#    *
#   /|\
#  1 2 +
#     / \
#    3   4
t = Tree('*', [Tree('1'),
               Tree('2'),
               Tree('+', [Tree('3'),
                          Tree('4')])])
Руда Моура
источник
Удивительно, но это можно легко использовать и как график! Единственная проблема, которую я видел: как я могу отличить левый узел от правого узла?
Анджело Полотто
3
По детскому указателю. В этом случае слева всегда будут дети [0].
Фрейнд Аллейн
38

Можешь попробовать:

from collections import defaultdict
def tree(): return defaultdict(tree)
users = tree()
users['harold']['username'] = 'hrldcpr'
users['handler']['username'] = 'matthandlersux'

Как предлагается здесь: https://gist.github.com/2012250

Ib33X
источник
если вы хотите расширить до произвольного количества уровней, проверьте: stackoverflow.com/a/43237270/511809
natbusa
это затеняет хэш встроенной функции.
Tritium21
20
class Node:
    """
    Class Node
    """
    def __init__(self, value):
        self.left = None
        self.data = value
        self.right = None

class Tree:
    """
    Class tree will provide a tree as well as utility functions.
    """

    def createNode(self, data):
        """
        Utility function to create a node.
        """
        return Node(data)

    def insert(self, node , data):
        """
        Insert function will insert a node into tree.
        Duplicate keys are not allowed.
        """
        #if tree is empty , return a root node
        if node is None:
            return self.createNode(data)
        # if data is smaller than parent , insert it into left side
        if data < node.data:
            node.left = self.insert(node.left, data)
        elif data > node.data:
            node.right = self.insert(node.right, data)

        return node


    def search(self, node, data):
        """
        Search function will search a node into tree.
        """
        # if root is None or root is the search data.
        if node is None or node.data == data:
            return node

        if node.data < data:
            return self.search(node.right, data)
        else:
            return self.search(node.left, data)



    def deleteNode(self,node,data):
        """
        Delete function will delete a node into tree.
        Not complete , may need some more scenarion that we can handle
        Now it is handling only leaf.
        """

        # Check if tree is empty.
        if node is None:
            return None

        # searching key into BST.
        if data < node.data:
            node.left = self.deleteNode(node.left, data)
        elif data > node.data:
            node.right = self.deleteNode(node.right, data)
        else: # reach to the node that need to delete from BST.
            if node.left is None and node.right is None:
                del node
            if node.left == None:
                temp = node.right
                del node
                return  temp
            elif node.right == None:
                temp = node.left
                del node
                return temp

        return node






    def traverseInorder(self, root):
        """
        traverse function will print all the node in the tree.
        """
        if root is not None:
            self.traverseInorder(root.left)
            print root.data
            self.traverseInorder(root.right)

    def traversePreorder(self, root):
        """
        traverse function will print all the node in the tree.
        """
        if root is not None:
            print root.data
            self.traversePreorder(root.left)
            self.traversePreorder(root.right)

    def traversePostorder(self, root):
        """
        traverse function will print all the node in the tree.
        """
        if root is not None:
            self.traversePostorder(root.left)
            self.traversePostorder(root.right)
            print root.data


def main():
    root = None
    tree = Tree()
    root = tree.insert(root, 10)
    print root
    tree.insert(root, 20)
    tree.insert(root, 30)
    tree.insert(root, 40)
    tree.insert(root, 70)
    tree.insert(root, 60)
    tree.insert(root, 80)

    print "Traverse Inorder"
    tree.traverseInorder(root)

    print "Traverse Preorder"
    tree.traversePreorder(root)

    print "Traverse Postorder"
    tree.traversePostorder(root)


if __name__ == "__main__":
    main()
Шивам Гарг
источник
3
Можете ли вы добавить несколько заметок, чтобы представить свой код и свою реализацию?
Мишель д'Амико
Спасибо за полную реализацию Binary Tree с функциями утилит. Поскольку это Python 2, я создал суть для реализации двоичного дерева (Py3) для людей, которым нужна версия Python 3.
CᴴᴀZ
16

Деревья не встроены, но вы можете легко сконструировать их, создав подкласс типа Node из List и написав методы обхода. Если вы сделаете это, я нашел пополам полезным.

Есть также много реализаций на PyPi которые вы можете просмотреть.

Если я правильно помню, стандартная библиотека Python не включает древовидные структуры данных по той же причине, что и библиотека базовых классов .NET: локальность памяти уменьшается, что приводит к большему количеству пропусков кэша. На современных процессорах обычно быстрее просто помещать большой объем памяти в кеш, а структуры данных с «указателем» сводят на нет преимущества.

Джастин Р.
источник
2
К вашему сведению: переплетения переплетаются с ненавистью к Boost. По-видимому, иметь дело с ОГРОМНОЙ болью, особенно с тех пор, как поддержка была прекращена. Поэтому я бы рекомендовал держаться подальше от
inspectorG4dget
Спасибо. У меня лично не было никаких проблем, но я не хочу вводить в заблуждение, поэтому я удалил эту ссылку.
Джастин Р.
11

Я реализовал корневое дерево как словарь {child:parent}. Так, например, с корневым узлом 0дерево может выглядеть так:

tree={1:0, 2:0, 3:1, 4:2, 5:3}

Эта структура позволила довольно легко идти вверх по пути от любого узла к корню, что было актуально для проблемы, над которой я работал.

лапа
источник
1
Я так и думал об этом, пока не увидел ответ. Хотя, так как дерево является родителем с двумя детьми, и если вы хотите пойти вниз, вы можете сделать {parent:[leftchild,rightchild]}.
JFA
1
Другой способ - использовать списки списков, где первый (или более) элемент в списке является значением узла, а следующие два вложенных списка представляют его левое и правое поддеревья (или более для n-арного дерева).
pepr
9

Ответ Грега Хьюгилла великолепен, но если вам нужно больше узлов на уровень, вы можете использовать список | словарь для их создания: а затем использовать метод для доступа к ним по имени или по порядку (например, id)

class node(object):
    def __init__(self):
        self.name=None
        self.node=[]
        self.otherInfo = None
        self.prev=None
    def nex(self,child):
        "Gets a node by number"
        return self.node[child]
    def prev(self):
        return self.prev
    def goto(self,data):
        "Gets the node by name"
        for child in range(0,len(self.node)):
            if(self.node[child].name==data):
                return self.node[child]
    def add(self):
        node1=node()
        self.node.append(node1)
        node1.prev=self
        return node1

Теперь просто создайте рут и создайте его: ex:

tree=node()  #create a node
tree.name="root" #name it root
tree.otherInfo="blue" #or what ever 
tree=tree.add() #add a node to the root
tree.name="node1" #name it

    root
   /
child1

tree=tree.add()
tree.name="grandchild1"

       root
      /
   child1
   /
grandchild1

tree=tree.prev()
tree=tree.add()
tree.name="gchild2"

          root
           /
        child1
        /    \
grandchild1 gchild2

tree=tree.prev()
tree=tree.prev()
tree=tree.add()
tree=tree.name="child2"

              root
             /   \
        child1  child2
       /     \
grandchild1 gchild2


tree=tree.prev()
tree=tree.goto("child1") or tree=tree.nex(0)
tree.name="changed"

              root
              /   \
         changed   child2
        /      \
  grandchild1  gchild2

Этого должно быть достаточно, чтобы вы начали выяснять, как сделать эту работу

Bruno
источник
В этом ответе чего-то не хватает, я пробовал это решение в течение последних 2 дней, и я думаю, что у вас есть некоторый логический ход в методе добавления объектов. Я отправлю свой ответ на этот вопрос, пожалуйста, проверьте это и дайте мне знать, если я могу помочь.
MAULIK MODI
8
class Tree(dict):
    """A tree implementation using python's autovivification feature."""
    def __missing__(self, key):
        value = self[key] = type(self)()
        return value

    #cast a (nested) dict to a (nested) Tree class
    def __init__(self, data={}):
        for k, data in data.items():
            if isinstance(data, dict):
                self[k] = type(self)(data)
            else:
                self[k] = data

работает как словарь, но предоставляет столько вложенных диктов, сколько вы хотите. Попробуйте следующее:

your_tree = Tree()

your_tree['a']['1']['x']  = '@'
your_tree['a']['1']['y']  = '#'
your_tree['a']['2']['x']  = '$'
your_tree['a']['3']       = '%'
your_tree['b']            = '*'

доставит вложенный диктат ... который действительно работает как дерево.

{'a': {'1': {'x': '@', 'y': '#'}, '2': {'x': '$'}, '3': '%'}, 'b': '*'}

... Если у вас уже есть диктат, он будет преобразовывать каждый уровень в дерево:

d = {'foo': {'amy': {'what': 'runs'} } }
tree = Tree(d)

print(d['foo']['amy']['what']) # returns 'runs'
d['foo']['amy']['when'] = 'now' # add new branch

Таким образом, вы можете редактировать / добавлять / удалять каждый уровень диктовок по своему усмотрению. Все методы dict для обхода и т. Д. Все еще применяются.

natbusa
источник
2
Есть ли причина, по которой вы решили расширить dictвместо defaultdict? Судя по моим тестам, расширение defaultdictвместо dict, а затем добавление self.default_factory = type(self)в начало init должно работать точно так же.
Роб Роуз
я, наверное, что-то здесь упускаю, как вы перемещаетесь по этой структуре? например, очень трудно переходить от детей к родителям или братьям и сестрам
Штормссон
6

Я реализовал деревья с помощью вложенных диктов. Это довольно легко сделать, и это сработало для меня с довольно большими наборами данных. Я разместил образец ниже, и вы можете увидеть больше в коде Google

  def addBallotToTree(self, tree, ballotIndex, ballot=""):
    """Add one ballot to the tree.

    The root of the tree is a dictionary that has as keys the indicies of all 
    continuing and winning candidates.  For each candidate, the value is also
    a dictionary, and the keys of that dictionary include "n" and "bi".
    tree[c]["n"] is the number of ballots that rank candidate c first.
    tree[c]["bi"] is a list of ballot indices where the ballots rank c first.

    If candidate c is a winning candidate, then that portion of the tree is
    expanded to indicate the breakdown of the subsequently ranked candidates.
    In this situation, additional keys are added to the tree[c] dictionary
    corresponding to subsequently ranked candidates.
    tree[c]["n"] is the number of ballots that rank candidate c first.
    tree[c]["bi"] is a list of ballot indices where the ballots rank c first.
    tree[c][d]["n"] is the number of ballots that rank c first and d second.
    tree[c][d]["bi"] is a list of the corresponding ballot indices.

    Where the second ranked candidates is also a winner, then the tree is 
    expanded to the next level.  

    Losing candidates are ignored and treated as if they do not appear on the 
    ballots.  For example, tree[c][d]["n"] is the total number of ballots
    where candidate c is the first non-losing candidate, c is a winner, and
    d is the next non-losing candidate.  This will include the following
    ballots, where x represents a losing candidate:
    [c d]
    [x c d]
    [c x d]
    [x c x x d]

    During the count, the tree is dynamically updated as candidates change
    their status.  The parameter "tree" to this method may be the root of the
    tree or may be a sub-tree.
    """

    if ballot == "":
      # Add the complete ballot to the tree
      weight, ballot = self.b.getWeightedBallot(ballotIndex)
    else:
      # When ballot is not "", we are adding a truncated ballot to the tree,
      # because a higher-ranked candidate is a winner.
      weight = self.b.getWeight(ballotIndex)

    # Get the top choice among candidates still in the running
    # Note that we can't use Ballots.getTopChoiceFromWeightedBallot since
    # we are looking for the top choice over a truncated ballot.
    for c in ballot:
      if c in self.continuing | self.winners:
        break # c is the top choice so stop
    else:
      c = None # no candidates left on this ballot

    if c is None:
      # This will happen if the ballot contains only winning and losing
      # candidates.  The ballot index will not need to be transferred
      # again so it can be thrown away.
      return

    # Create space if necessary.
    if not tree.has_key(c):
      tree[c] = {}
      tree[c]["n"] = 0
      tree[c]["bi"] = []

    tree[c]["n"] += weight

    if c in self.winners:
      # Because candidate is a winner, a portion of the ballot goes to
      # the next candidate.  Pass on a truncated ballot so that the same
      # candidate doesn't get counted twice.
      i = ballot.index(c)
      ballot2 = ballot[i+1:]
      self.addBallotToTree(tree[c], ballotIndex, ballot2)
    else:
      # Candidate is in continuing so we stop here.
      tree[c]["bi"].append(ballotIndex)
gaefan
источник
5

Я опубликовал реализацию дерева Python [3] на своем сайте: http://www.quesucede.com/page/show/id/python_3_tree_implementation .

Надеюсь, что это полезно,

Хорошо, вот код:

import uuid

def sanitize_id(id):
    return id.strip().replace(" ", "")

(_ADD, _DELETE, _INSERT) = range(3)
(_ROOT, _DEPTH, _WIDTH) = range(3)

class Node:

    def __init__(self, name, identifier=None, expanded=True):
        self.__identifier = (str(uuid.uuid1()) if identifier is None else
                sanitize_id(str(identifier)))
        self.name = name
        self.expanded = expanded
        self.__bpointer = None
        self.__fpointer = []

    @property
    def identifier(self):
        return self.__identifier

    @property
    def bpointer(self):
        return self.__bpointer

    @bpointer.setter
    def bpointer(self, value):
        if value is not None:
            self.__bpointer = sanitize_id(value)

    @property
    def fpointer(self):
        return self.__fpointer

    def update_fpointer(self, identifier, mode=_ADD):
        if mode is _ADD:
            self.__fpointer.append(sanitize_id(identifier))
        elif mode is _DELETE:
            self.__fpointer.remove(sanitize_id(identifier))
        elif mode is _INSERT:
            self.__fpointer = [sanitize_id(identifier)]

class Tree:

    def __init__(self):
        self.nodes = []

    def get_index(self, position):
        for index, node in enumerate(self.nodes):
            if node.identifier == position:
                break
        return index

    def create_node(self, name, identifier=None, parent=None):

        node = Node(name, identifier)
        self.nodes.append(node)
        self.__update_fpointer(parent, node.identifier, _ADD)
        node.bpointer = parent
        return node

    def show(self, position, level=_ROOT):
        queue = self[position].fpointer
        if level == _ROOT:
            print("{0} [{1}]".format(self[position].name,
                                     self[position].identifier))
        else:
            print("\t"*level, "{0} [{1}]".format(self[position].name,
                                                 self[position].identifier))
        if self[position].expanded:
            level += 1
            for element in queue:
                self.show(element, level)  # recursive call

    def expand_tree(self, position, mode=_DEPTH):
        # Python generator. Loosly based on an algorithm from 'Essential LISP' by
        # John R. Anderson, Albert T. Corbett, and Brian J. Reiser, page 239-241
        yield position
        queue = self[position].fpointer
        while queue:
            yield queue[0]
            expansion = self[queue[0]].fpointer
            if mode is _DEPTH:
                queue = expansion + queue[1:]  # depth-first
            elif mode is _WIDTH:
                queue = queue[1:] + expansion  # width-first

    def is_branch(self, position):
        return self[position].fpointer

    def __update_fpointer(self, position, identifier, mode):
        if position is None:
            return
        else:
            self[position].update_fpointer(identifier, mode)

    def __update_bpointer(self, position, identifier):
        self[position].bpointer = identifier

    def __getitem__(self, key):
        return self.nodes[self.get_index(key)]

    def __setitem__(self, key, item):
        self.nodes[self.get_index(key)] = item

    def __len__(self):
        return len(self.nodes)

    def __contains__(self, identifier):
        return [node.identifier for node in self.nodes
                if node.identifier is identifier]

if __name__ == "__main__":

    tree = Tree()
    tree.create_node("Harry", "harry")  # root node
    tree.create_node("Jane", "jane", parent = "harry")
    tree.create_node("Bill", "bill", parent = "harry")
    tree.create_node("Joe", "joe", parent = "jane")
    tree.create_node("Diane", "diane", parent = "jane")
    tree.create_node("George", "george", parent = "diane")
    tree.create_node("Mary", "mary", parent = "diane")
    tree.create_node("Jill", "jill", parent = "george")
    tree.create_node("Carol", "carol", parent = "jill")
    tree.create_node("Grace", "grace", parent = "bill")
    tree.create_node("Mark", "mark", parent = "jane")

    print("="*80)
    tree.show("harry")
    print("="*80)
    for node in tree.expand_tree("harry", mode=_WIDTH):
        print(node)
    print("="*80)
Бретт Кромкамп
источник
4

Если кому-то нужен более простой способ сделать это, дерево является только рекурсивно-вложенным списком (так как множество не является хешируемым):

[root, [child_1, [[child_11, []], [child_12, []]], [child_2, []]]]

Где каждая ветвь представляет собой пару, [ object, [children] ]
а каждый лист представляет собой пару:[ object, [] ]

Но если вам нужен класс с методами, вы можете использовать anytree.

Хьюго Тренто
источник
1

Какие операции вам нужны? В Python часто есть хорошее решение, использующее dict или список с модулем bisect.

Существует множество реализаций дерева в PyPI , и многие типы деревьев почти тривиальны, чтобы реализовать себя в чистом Python. Однако это редко необходимо.

Майк Грэм
источник
0

Другая реализация дерева, основанная на ответе Бруно :

class Node:
    def __init__(self):
        self.name: str = ''
        self.children: List[Node] = []
        self.parent: Node = self

    def __getitem__(self, i: int) -> 'Node':
        return self.children[i]

    def add_child(self):
        child = Node()
        self.children.append(child)
        child.parent = self
        return child

    def __str__(self) -> str:
        def _get_character(x, left, right) -> str:
            if x < left:
                return '/'
            elif x >= right:
                return '\\'
            else:
                return '|'

        if len(self.children):
            children_lines: Sequence[List[str]] = list(map(lambda child: str(child).split('\n'), self.children))
            widths: Sequence[int] = list(map(lambda child_lines: len(child_lines[0]), children_lines))
            max_height: int = max(map(len, children_lines))
            total_width: int = sum(widths) + len(widths) - 1
            left: int = (total_width - len(self.name) + 1) // 2
            right: int = left + len(self.name)

            return '\n'.join((
                self.name.center(total_width),
                ' '.join(map(lambda width, position: _get_character(position - width // 2, left, right).center(width),
                             widths, accumulate(widths, add))),
                *map(
                    lambda row: ' '.join(map(
                        lambda child_lines: child_lines[row] if row < len(child_lines) else ' ' * len(child_lines[0]),
                        children_lines)),
                    range(max_height))))
        else:
            return self.name

И пример того, как его использовать:

tree = Node()
tree.name = 'Root node'
tree.add_child()
tree[0].name = 'Child node 0'
tree.add_child()
tree[1].name = 'Child node 1'
tree.add_child()
tree[2].name = 'Child node 2'
tree[1].add_child()
tree[1][0].name = 'Grandchild 1.0'
tree[2].add_child()
tree[2][0].name = 'Grandchild 2.0'
tree[2].add_child()
tree[2][1].name = 'Grandchild 2.1'
print(tree)

Который должен вывести:

                        Корневой узел                        
     / / \              
Дочерний узел 0 Дочерний узел 1 Дочерний узел 2        
                   | / \       
             Внук 1.0 внук 2.0 внук 2.1
Соломон Уцко
источник
0

Я предлагаю библиотеку networkx .

NetworkX - это пакет Python для создания, управления и изучения структуры, динамики и функций сложных сетей.

Пример построения дерева:

import networkx as nx
G = nx.Graph()
G.add_edge('A', 'B')
G.add_edge('B', 'C')
G.add_edge('B', 'D')
G.add_edge('A', 'E')
G.add_edge('E', 'F')

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

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

Гал Авинери
источник
-2

Если вы хотите создать древовидную структуру данных, то сначала вы должны создать объект treeElement. Если вы создаете объект treeElement, вы можете решить, как будет вести себя ваше дерево.

Для этого используется класс TreeElement:

class TreeElement (object):

def __init__(self):
    self.elementName = None
    self.element = []
    self.previous = None
    self.elementScore = None
    self.elementParent = None
    self.elementPath = []
    self.treeLevel = 0

def goto(self, data):
    for child in range(0, len(self.element)):
        if (self.element[child].elementName == data):
            return self.element[child]

def add(self):

    single_element = TreeElement()
    single_element.elementName = self.elementName
    single_element.previous = self.elementParent
    single_element.elementScore = self.elementScore
    single_element.elementPath = self.elementPath
    single_element.treeLevel = self.treeLevel

    self.element.append(single_element)

    return single_element

Теперь мы должны использовать этот элемент для создания дерева, в этом примере я использую дерево A *.

class AStarAgent(Agent):
# Initialization Function: Called one time when the game starts
def registerInitialState(self, state):
    return;

# GetAction Function: Called with every frame
def getAction(self, state):

    # Sorting function for the queue
    def sortByHeuristic(each_element):

        if each_element.elementScore:
            individual_score = each_element.elementScore[0][0] + each_element.treeLevel
        else:
            individual_score = admissibleHeuristic(each_element)

        return individual_score

    # check the game is over or not
    if state.isWin():
        print('Job is done')
        return Directions.STOP
    elif state.isLose():
        print('you lost')
        return Directions.STOP

    # Create empty list for the next states
    astar_queue = []
    astar_leaf_queue = []
    astar_tree_level = 0
    parent_tree_level = 0

    # Create Tree from the give node element
    astar_tree = TreeElement()
    astar_tree.elementName = state
    astar_tree.treeLevel = astar_tree_level
    astar_tree = astar_tree.add()

    # Add first element into the queue
    astar_queue.append(astar_tree)

    # Traverse all the elements of the queue
    while astar_queue:

        # Sort the element from the queue
        if len(astar_queue) > 1:
            astar_queue.sort(key=lambda x: sortByHeuristic(x))

        # Get the first node from the queue
        astar_child_object = astar_queue.pop(0)
        astar_child_state = astar_child_object.elementName

        # get all legal actions for the current node
        current_actions = astar_child_state.getLegalPacmanActions()

        if current_actions:

            # get all the successor state for these actions
            for action in current_actions:

                # Get the successor of the current node
                next_state = astar_child_state.generatePacmanSuccessor(action)

                if next_state:

                    # evaluate the successor states using scoreEvaluation heuristic
                    element_scored = [(admissibleHeuristic(next_state), action)]

                    # Increase the level for the child
                    parent_tree_level = astar_tree.goto(astar_child_state)
                    if parent_tree_level:
                        astar_tree_level = parent_tree_level.treeLevel + 1
                    else:
                        astar_tree_level += 1

                    # create tree for the finding the data
                    astar_tree.elementName = next_state
                    astar_tree.elementParent = astar_child_state
                    astar_tree.elementScore = element_scored
                    astar_tree.elementPath.append(astar_child_state)
                    astar_tree.treeLevel = astar_tree_level
                    astar_object = astar_tree.add()

                    # If the state exists then add that to the queue
                    astar_queue.append(astar_object)

                else:
                    # Update the value leaf into the queue
                    astar_leaf_state = astar_tree.goto(astar_child_state)
                    astar_leaf_queue.append(astar_leaf_state)

Вы можете добавлять / удалять любые элементы из объекта, но сделать структуру взаимной.

МАУЛИК ​​МОДИ
источник
-4
def iterative_bfs(graph, start):
    '''iterative breadth first search from start'''
    bfs_tree = {start: {"parents":[], "children":[], "level":0}}
    q = [start]
    while q:
        current = q.pop(0)
        for v in graph[current]:
            if not v in bfs_tree:
                bfs_tree[v]={"parents":[current], "children":[], "level": bfs_tree[current]["level"] + 1}
                bfs_tree[current]["children"].append(v)
                q.append(v)
            else:
                if bfs_tree[v]["level"] > bfs_tree[current]["level"]:
                    bfs_tree[current]["children"].append(v)
                    bfs_tree[v]["parents"].append(current)
Гаган Нирмал
источник
Это, кажется, не отвечает на вопрос вообще любым читаемым способом.
AlBlue