Here is my code:
class Node:
nodes = {}
def __init__(self, name):
self.name = name
self.parent = []
self.children = []
Node.nodes[self.name] = self
def addParent(self, parent):
print "adding parent %s for %s " % (parent, self.name)
self.parent.append(parent)
print self.parent
def addChild(self, child):
self.children.append(child)
def removeParent(self, parent):
try:
self.parent.remove(parent)
except:
pass
def removeChild(self, child):
try:
self.children.remove(child)
except:
pass
def lookup(obj):
print "calling look up"
Node.nodes.get(obj)
def create_node(obj):
return lookup(obj) or Node(obj)
# Tree has Nodes
class Tree:
trees = {}
def __init__(self, name, root):
self.name = name
self.root = root
self.size = 1
self.nodes = set() # tree has unique nodes
self.nodes.add(root)
Tree.trees[self.name] = self
def addNode(self, node):
self.nodes.add(node)
self.size += 1
def removeNode(self, node):
try:
self.nodes.remove(node)
except:
return
self.size -= 1
def setRoot(self, root):
self.root = root
def print_tree(self):
for i in self.nodes:
if i == self.root.name:
print "root: %s" % i
else:
print i
def main():
roota = create_node("a")
ta = Tree("a", roota)
childaa = create_node("a_a")
roota.addChild(childaa)
childaa.addParent(roota)
ta.addNode(childaa)
childab = create_node("a_b")
roota.addChild(childab)
childab.addParent(roota)
ta.addNode(childab)
# make one of the child of a root
rootb = create_node("a_a") # should give me a node that already exists from the above tree
tb = Tree("a_a", rootb)
childbb = create_node("a_b") # this node should have two parents now, a and a_a
rootb.addChild(childbb)
childbb.addParent(rootb)
tb.addNode(childbb)
for node in Node.nodes.itervalues():
print "Name: %s" % node.name
if node.parent:
print "Parent: %s" % [parent.name for parent in node.parent]
else:
print "Parent: %s" % node.parent
print "Children: ", [node.name for node in node.children]
print ""
if __name__ == '__main__':
main()
And the output of the script:
Name: a
Parent: []
Children: ['a_a', 'a_b']
Name: a_a
Parent: []
Children: ['a_b']
Name: a_b
Parent: ['a_a']
Children: []
a_a should have parent a. line 80 is adding a as a parent for a_a
a_b should have parent a_a and a. line 85 is adding a as a parent for a_b
can someone explain to me why that's not the case in this code?
And desired the output of the script:
Name: a
Parent: []
Children: ['a_a', 'a_b']
Name: a_a
Parent: ['a']
Children: ['a_b']
Name: a_b
Parent: ['a', 'a_a']
Children: []
A tree is a directed cyclic-free graph. Each node of a tree is itself a tree, hence you don't need two classes for tree and node (except you want to give some metainfo to your tree).
It is sufficient to keep track either of children or of the parent, but for convenience sake (e.g. transversing the tree in both directions) you can save both. But if you do, you have to take care that isParent(a,b) be tautological to isChild(b,a). In your code, if you add a node and don't manually set its parent, your tree goes haywire.
Said this, "# this node should have two parents now, a and a_a" doesn't make much sense if we are talking about trees.
A basic tree structure looks like this (not validating for cycles):
class Tree:
def __init__ (self, payload):
self.payload = payload
self.children = set ()
self.parent = None
def __iadd__ (self, child):
if child.parent: raise Exception ('Node already attached')
child.parent = self #update parent
self.children.add (child) #update children's list
return self
def detach (self):
if not self.parent: return
self.parent.children.remove (self) #update parent's children's list
self.parent = None #update self
def pprint (self, level = 0):
print (' ' * level + self.payload)
for child in self.children:
child.pprint (level + 2)
And an example is this:
root = Tree ('root')
a = Tree ('A')
b = Tree ('B')
c = Tree ('C')
root += a
root += b
b += c
root.pprint ()
c.detach ()
a += c
root.pprint ()
I hope you can take some ideas from this snippet about how to build a tree.
Related
I have below method where self contains a data structure as below
self.place = "India"
self.children = ["Tamil Nadu", "Karnataka"]
self.parent
Method
def get_node(self, value):
if value is None:
return self
if self.place == value:
return self
for node in self.children:
if node.place == value:
return node
elif len(node.children) > 0:
return node.get_node(value)
So via recursion, I am iterating on all possible child nodes to find the node I am looking for via return node.get_node(value) but I observed that, iteration happening via "Tamil Nadu" but not via "Karnataka".
I understood that, it took the first element of the list and then continued from there, but not coming back to 2nd element of the list.
is this expected behavior from recursion or am I doing something wrong ?
Full code( In case needed for testing)
class TreeNode:
def __init__(self, place):
self.place = place
self.children = []
self.parent = None
def add_child(self, child):
child.parent = self
self.children.append(child)
def print_tree(self):
prefix = ""
if self.parent is None:
print(self.place)
else:
prefix = prefix + (" " * self.get_level() * 3)
prefix = prefix + "|__"
print(prefix + self.place)
for child in self.children:
child.print_tree()
def get_level(self):
level = 0
p = self.parent
while p:
level = level + 1
p = p.parent
return level
def get_node(self, value):
if value is None:
return self
if self.place == value:
return self
for node in self.children:
if node.place == value:
return node
elif len(node.children) > 0:
return node.get_node(value)
def tree_map(self, nodes):
for node in nodes:
self.add_child(TreeNode(node))
def build_places():
root = TreeNode("Global")
india = TreeNode("India")
usa = TreeNode("USA")
root.add_child(india)
root.add_child(usa)
india_nodes = ["Gujarat" ,"Karnataka"]
gujarath_nodes = [ "Ahmedabad", "Baroda"]
karnataka_nodes = ["Bangalore", "Mysore"]
usa_nodes = ["New Jersey", "California"]
newjersey_nodes = ["Princeton", "Trenton"]
california_nodes = ["San Franciso", "Mountain View", "Palo Alto"]
for node in india_nodes:
india.add_child(TreeNode(node))
for node in usa_nodes:
usa.add_child(TreeNode(node))
gujarath_node = root.get_node("Gujarat")
print(gujarath_node.place)
for node in gujarath_nodes:
gujarath_node.add_child(TreeNode(node))
karnataka_node = root.get_node("Karnataka")
print(karnataka_node.place)
return root
if __name__ == "__main__":
root = build_places()
root.print_tree()
The problem is that in your loop you are always exiting the loop in its first iteration (when the node has at least some children). You should only exit on success, not when the recursive call comes back without success.
So change the loop to this:
for node in self.children:
if node.place == value:
return node
elif len(node.children) > 0:
result = node.get_node(value)
if result:
return result
Secondly, there is a strange base case you have at the start of this function. I would replace this:
if value is None:
return self
With:
if value is None:
return None
...since you didn't look for the value in that case: so then (in my opinion) it is not right to return a node instance (which might have any value -- you didn't verify it). It seems more consistent to return None or to remove this whole if block and not treat None in a special way.
I want to figure out how to print all nodes at a specific level. Right now, I can get to that level but I can only print out a part of the nodes. How would I get it to print all the nodes from all branches instead of nodes from one branch? I tried recursively calling get_level_nodes but it keeps outputting an error.
import random
class Node(object):
def __init__(self, value):
self.value = value
self.children = []
self.parent = None
def create_children(self, infects, depth):
# root node
if depth == 0:
return
for i in range(infects):
rand2 = random.random()
if rand2 <= 0.37:
if rand2 <= 0.02:
child = Node('NA')
else:
child = Node('CA')
else:
if rand2 <= 0.5:
child = Node('NS')
else:
child = Node('CS')
child.parent = self
child.grandparent = self.parent
self.children.append(child)
# recursive call to create more child nodes
child.create_children(infects, depth-1)
def tree_level(self):
level = 0
p = self.parent
while p:
level += 1
p = p.parent
return level
def print_tree(self):
spaces = ' ' * self.tree_level() * 2
prefix = spaces + '|__' if self.parent else ''
print(prefix + self.value, self.quarantined)
if self.children:
for child in self.children:
if child.value != None:
child.print_tree()
def get_level_nodes(self, cur_level):
level = 0
c = self.children
while c:
level += 1
c = self.children
if level == cur_level:
return c
if __name__ == "__main__":
rand1 = random.random()
if rand1 <= .35:
a = Node('CA')
else:
a = Node('CA')
a.create_children(2, 5) # create_children(R0, depth)
for child in a.get_level_nodes(4):
print(child.value)
a.print_tree()
Your get_level_nodes function has some issues:
c never changes value: it always represents self.children, so you are not actually moving down in the tree. You should somewhere iterate over those children and extend your collection of nodes with the children of these children.
You start out with self.children, but that list of nodes already represents the second level in the tree. You should foresee that the function can return the top-level of the tree, i.e. a list with just the root node in it.
I'll assume that you use the definition of "level" as specified in Wikipedia, although other definitions exist:
Level
1 + the number of edges between a node and the root, i.e. (depth + 1)
Solution:
def get_level_nodes(self, cur_level):
nodes = [self]
for i in range(cur_level-1): # assuming that cur_level is at least 1
children = []
for node in nodes:
children.extend(node.children)
nodes = children
return nodes
I have a basic class containing two attributes 'Name' and 'Children.
class Node():
def __init__(self, name):
self.name = name
self.children = []
I have a core root node as follows:
# Create Master Root Node
root = Node('root')
How would I go about creating a function that I could pass a path to a specific node in the tree, and the function return that node.
However if that node doesn't exist it would create/append to the tree, and still return the node.
path = ['Leslie','Marie','Tori'] # simple example
def get_node_by_path(path=[])...
If a path failed before reaching the end of the path, it would automatically create the missing nodes in order to make the entire path complete.
path = ['Leslie','Marie','Tori','Kevin'] # more complex requires two nodes to be created
def get_node_by_path(path=[])...
I'd do something like this. It's a non recursive solution.
def get_node_by_path(path):
cur_node = root
for elem_name in path:
found = False
for child in cur_node.children:
if child.name == elem_name:
cur_node = child
found = True
break
if not found:
new_node = Node(elem_name)
cur_node.children.append(new_node)
cur_node = new_node
return cur_node
class Node:
def __init__(self, name):
self.name = name
self.children = []
def path_to(self, path):
if not path:
return self
head, *tail = path
for child in self.children:
if child.name == head:
return child.path_to(tail)
newborn = Node(head)
self.children.append(newborn)
return newborn.path_to(tail)
Here's a solution that recursively considers whether the first name in the list is a child of the current node.
For Python 2, head, *tail = path can be replaced with
head = path[0]
tail = path[1:]
start with the last dag object and go to the root
class Node():
def __init__(self, name = "", childern = []):
self.name = name
self.children = childern
print ("Node Name: {0} Childern Nodes {1}".format(self.name, self.children))
def get_node_by_path(path=[]):
for c,n in enumerate(reversed(path)):
if not c:
Node(name = n)
else:
Node(name = n, childern = path[-c:])
path = ['root', 'Leslie','Marie','Tori','Kevin']
get_node_by_path(path)
I am currently developing an AI system in python to solve the bloxorz game using the A* search algorithm.
Naturally, the algorithm stores the nodes in a priority queue,but when i try to get() an element from the queue, it returns an int instead of the object. As I am very new to python, I would appreciate it if someone can clarify.
My A* algorithm:
class Astar:
def __init__(self, start):
self.path = []
self.visitedQueue = []
"""hold visited in a queue to avoid duplicates"""
self.priorityQueue = PriorityQueue()
self.start = start
def Solve(self):
"""the a* algorithm"""
StartNode = Node_Map(self.start, 0, self.start)
count = 0
self.priorityQueue.put(0, count, StartNode)
while not self.path and self.priorityQueue.qsize():
closestChild = self.priorityQueue.get()[2]
closestChild.createChildren()
self.visitedQueue.append(closestChild.matrix)
for child in closestChild.children:
if child.matrix not in self.visitedQueue:
count += 1
if child.getH == 0:
self.path = child.path
break
self.priorityQueue.put(child.getH+count, count, child)
""" put in priority queue according to f(n)=h(n)+g(n)"""
if not self.path:
print("goal not possible")
return self.path
My Node class and Node_Map class:
class Node(object):
def __init__(self, matrix, parent, start=0):
self.children = []
self.matrix = {}
self.parent = parent
self.xPos = 0
self.yPos = 0
self.goalX = 0
self.goalY = 0
if parent:
self.path = parent.path[:]
self.start = parent.start
self.path.append = [matrix]
else:
self.path = [matrix]
self.start = start
def getDist(self):
""" abstract function to get our estimated distance to the goal"""
pass
def createChildren(self):
"""absract to create children from successor actions"""
pass
class Node_Map(Node):
def __init__(self, matrix, parent, start=0):
super(Node_Map, self).__init__(matrix, parent, start)
self.h = self.getH()
priorityQueue.put(child.getH+count, count, child)
The above line calls put with the arguments: item=child.getH+count, block=count, and timeout=child. As a result, only child.getH+count is be considered as the 'item' that get will retrieve. Try putting all three objects into a tuple:
priorityQueue.put((child.getH+count, count, child))
This way, item will be the tuple (child.getH+count, count, child), and the other two arguments, block, and timeout, will stay as their default values (True and None, respectively).
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I want to build a general tree whose root node contains 'n' children, and those children may contain other children.....
A tree in Python is quite simple. Make a class that has data and a list of children. Each child is an instance of the same class. This is a general n-nary tree.
class Node(object):
def __init__(self, data):
self.data = data
self.children = []
def add_child(self, obj):
self.children.append(obj)
Then interact:
>>> n = Node(5)
>>> p = Node(6)
>>> q = Node(7)
>>> n.add_child(p)
>>> n.add_child(q)
>>> n.children
[<__main__.Node object at 0x02877FF0>, <__main__.Node object at 0x02877F90>]
>>> for c in n.children:
... print c.data
...
6
7
>>>
This is a very basic skeleton, not abstracted or anything. The actual code will depend on your specific needs - I'm just trying to show that this is very simple in Python.
I've published a Python [3] tree implementation on my site: http://www.quesucede.com/page/show/id/python_3_tree_implementation.
Hope it is of use,
Ok, here's the code:
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)
anytree
I recommend https://pypi.python.org/pypi/anytree
Example
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'))
Features
anytree has also a powerful API with:
simple tree creation
simple tree modification
pre-order tree iteration
post-order tree iteration
resolve relative and absolute node paths
walking from one node to an other.
tree rendering (see example above)
node attach/detach hookups
node = { 'parent':0, 'left':0, 'right':0 }
import copy
root = copy.deepcopy(node)
root['parent'] = -1
left = copy
just to show another thought on implementation if you stick to the "OOP"
class Node:
def __init__(self,data):
self.data = data
self.child = {}
def append(self, title, child):
self.child[title] = child
CEO = Node( ('ceo', 1000) )
CTO = ('cto',100)
CFO = ('cfo', 10)
CEO.append('left child', CTO)
CEO.append('right child', CFO)
print CEO.data
print ' ', CEO.child['left child']
print ' ', CEO.child['right child']