2009-09-06 2 views
0

Я - nooby. Я бы хотел поблагодарить Аллена Дауни, Джеффри Элкнера и Криса Майерса и «Как думать, как компьютерный ученый» за то, что я знаю.Python: манипулирование вспомогательными деревьями

Я создаю программу, основанную на генетике, для генерации уравнений, соответствующих определенной задаче.

класса Узла выглядит следующим образом:

class Node(object): 
    ''' 
    ''' 
    def __init__(self, cargo, left=None, right=None): 
     self.cargo = cargo 
     self.left = left 
     self.right = right 
     self.parent = None 
     self.branch = None 
     self.seq = 0 

    def __str__(self): 
     return str(self.cargo) 

    def copy(self): 
     return copy.deepcopy(self) 

У меня есть Tree класса, который содержит атрибут: self.data, который представляет собой ряд связанных узлов, образующих дерево, которое я могу пройти, чтобы произвести уравнение.

Чтобы выполнить кроссовер, я хотел бы иметь возможность менять поддеревья, выбранные случайным образом из двух экземпляров Tree.

Поскольку строится self.data, он создает словарь с последовательным ключом, удерживающим каждый узел в качестве значения. Одна такая запись выглядит следующим образом:

3: <__main__.Node object at 0x0167B6B0>} 

Я думал, что быть умным и просто выбрать Узел каждого из двух экземпляров дерева и обменивать их родительские node.left или node.right значения. Каждый узел записывает, является ли он левым или правым в свой атрибут node.branch.

Я не знаю, как обратиться к self.data(subnode), чтобы изменить его.

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

Я боюсь, что мне придется копировать и заменять каждое поддерево.

Любые комментарии будут оценены.

Спасибо,

Питер Стюарт

Nanaimo, Канада

ответ

0

Если я правильно понимаю, вы ищете что-то вроде этого ...

(я не проверял это.)

def swap_nodes(dict_1, key_1, dict_2, key_2): 
    node_1 = dict_1[key_1] 
    node_2 = dict_2[key_2] 

    # Update dicts and seq fields for the two nodes... 
    dict_1[key_1] = node_2 
    node_2.seq = key_1 
    dict_2[key_2] = node_1 
    node_1.seq = key_2 

    # Update the parents... 
    if node_1.branch == "left": 
     node_1.parent.left = node_2 
    else: 
     node_1.parent.right = node_2 

    if node_2.branch == "left": 
     node_2.parent.left = node_1 
    else: 
     node_2.parent.right = node_1 

    # Now update the branch and parent fields of the nodes... 
    node_1.branch, node_2.branch = node_2.branch, node_1.branch 
    node_1.parent, node_2.parent = node_2.parent, node_1.parent 
+0

Обратите внимание, что это, в отличие от Алекса , предполагает, что ни один из узлов не является корнем его дерева. – Anon

+0

(Чтобы справиться с этой возможностью, вы могли бы добавить случаи elif к родительским обновлениям, поэтому elses не поймают «правильные» и корневые случаи. – Anon

2

К сожалению, вы не предоставите намкласса, но давайте предположим, что это что-то вроде:

class Tree(object): 
    def __init__(self): 
    self.data = None 
    self.nextkey = 0 
    self.thedict = {} 

с различными атрибутами обновляются точно, когда новые узлы вставляются. Теперь, когда вы говорите об «адресе, сохраненном в словаре», ясно, что значение dict не является «адресом» - скорее, это объект Node (если вы определяете специальный метод __repr__ в своем узле, вы можете быть в состоянии чтобы увидеть это более четко, то, что вы видите, является представлением по умолчанию, используемым для всех объектов Python, тип которых не определяет или не наследует __repr__).

Таким образом, замена случайного поддерева между двумя разными деревьями требует только тщательного обновления всех избыточных частей информации, которые вы храните (и это должно ВСЕ быть в синхронизации).Кстати, было бы проще, если бы такие обновления были методами Tree и/или Node и поэтому использовались для любого из различных видов «редактирования» (вставки, удаления и т. Д.), А не были глубоко погружены в функцию, которая выполняет обновления как часть случайного обмена - это хорошая практика OO. Но это несколько проблема.

Вы также не говорите нам точно, как работает атрибут branch, я предполагаю, что это строка, «слева» или «справа» (если нет родителя, т. Е. Корневого узла).

Чтобы удалить поддерево, вам необходимо обновить: родительский узел, установив на None свой соответствующий атрибут; корень поддерева, установив None в его родительские и ветвящиеся атрибуты; И Дерево, удалив эту запись из атрибута дерева thedict. Вам также нужно будет запомнить, что такое родительский элемент и ветвь, чтобы иметь возможность вставить в это место другое поддерево. Поэтому ...:

def removeSubtreeFromTree(tree, keyindict): 
    subtreenode = tree.thedict.pop(keyindict) 
    parent, branch = subtreenode.parent, subtreenode.branch 
    # a sanity chech can't hurt...;-) 
    assert getattr(parent, branch) is subtreenode 
    subtreenode.parent, subtreenode.branch = None, None 
    setattr(parent, branch, None) 
    return subtreenode, parent, branch 

Теперь, чтобы добавить новое поддерево к данному родителю и ветви в дереве проще:

def addNewSubtree(tree, subtreenode, parent, branch): 
    # sanity checks R us 
    assert getattr(parent, branch) is None 
    assert subtreenode.parent is None 
    assert subtreenode.branch is None 
    setattr(parent, branch, subtreenode) 
    subtreenode.parent = parent 
    subtreenode.branch = branch 
    tree.thedict[tree.nextkey] = subtreenode 
    tree.nextkey += 1 

Примечание Вы не можете просто повторно использовать предыдущие ключи: там может быть «конфликтом» (предполагая, что ключи уникальны только в пределах одного заданного дерева ... если вы сделали их глобально уникальными, то вы действительно могли бы их повторно использовать).

И, наконец, можно выполнить эти две операции и немного больше вместе. Если вам никогда не нужно «обменивать» корень дерева, он проще (никакого специального случая, необходимого для работы с поддеревом без родителя ...), поэтому я временно предполагаю, что (если вы хотите больше общности, вам нужно будет кодировать в привередливые особых случаях - в идеале после рефакторинга вещи, чтобы быть методы, как я ранее предложил; -) ...:

def randomNonrootSubtree(tree): 
    # we're in trouble if the tree ONLY has a root w/no really SUB trees;-) 
    assert len(tree.thedict) > 1 
    while True: 
     thekey = random.choice(tree.thedict.keys()) 
     subtree = tree.thedict[thekey] 
     if subtree.parent: return thekey 

и наконец ...:

def theSwapper(t1, t2): 
    k1 = randomNonrootSubtree(t1) 
    k2 = randomNonrootSubtree(t2) 
    st1, p1, b1 = removeSubtreeFromTree(t1, k1) 
    st2, p2, b2 = removeSubtreeFromTree(t2, k2) 
    addNewSubtree(t1, st2, p1, b1) 
    addNewSubtree(t2, st1, p2, b2) 
Смежные вопросы