A general tree implementation? [closed] - python

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

Related

Get child node if exists otherwise create in Python

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)

int' object has no attribute '__getitem__' Python

This is the tree problem
class TreeProblem(Problem):
# methods exported to Search class ---------------------------------------------
# initial "state" of a tree is just its root
def initialState(self):
return self.root.id
# goal test is whether goal matches node label
def goalTest(self, state):
node = self.nodes[state]
return node.isgoal
# successors of a node are its children
def successorFn(self, state):
node = self.nodes[state]
if node.isTerminal():
return []
else:
return [self._contents('l', node.lchild), \
self._contents('r', node.rchild)]
# step cost state--[action]-->result is just the random cost associated with result
def stepCost(self, state, action, result):
node = self.nodes[result]
return node.cost
# no action is actually taken; we just print out the state for debugging
def takeAction(self, state, action):
print 'visit ', state
return 'visit', state
This is the Node class
class Node:
"""A node in a search tree. Contains a pointer to the parent (the node
that this is a successor of) and to the actual state for this node. Note
that if a state is arrived at by two paths, then there are two nodes with
the same state. Also includes the action that got us to this state, and
the total path_cost (also known as g) to reach the node. Other functions
may add an f and h value; see best_first_graph_search and astar_search for
an explanation of how the f and h values are handled. You will not need to
subclass this class."""
def __init__(self, state, parent=None, action=None, path_cost=0):
"Create a search tree Node, derived from a parent by an action."
# state = force_hashable(state)
self.update(self, state=state, parent=parent, action=action,
path_cost=path_cost, depth=0)
if parent:
self.depth = parent.depth + 1
def __repr__(self):
return "<Node %s>" % (self.state,)
def expand(self, problem):
"List the nodes reachable in one step from this node."
return [self.child_node(problem, action)
for action in problem.takeAction(self.state, self.action)]
#print problem
#return [Node(next, self, act,
# problem.stepCost(self.state, act, next[1]))
# for (act, next) in problem.successorFn(self.state)]
def child_node(self, problem, action):
"Fig. 3.10"
(act, next) = problem.successorFn(self.state)
print str(next[1]) + "\n"
return Node(next, self, action,
problem.stepCost(self.state, action, next[1]))
def solution(self):
"Return the sequence of actions to go from the root to this node."
return [node.action for node in self.path()[1:]]
def path(self):
"Return a list of nodes forming the path from the root to this node."
node, path_back = self, []
while node:
path_back.append(node)
node = node.parent
return list(reversed(path_back))
def update(self, x, **entries):
"""Update a dict, or an object with slots, according to `entries` dict.
>>> update({'a': 1}, a=10, b=20)
{'a': 10, 'b': 20}
>>> update(Struct(a=1), a=10, b=20)
Struct(a=10, b=20)
"""
if isinstance(x, dict):
x.update(entries)
else:
x.__dict__.update(entries)
return x
# We want for a queue of nodes in breadth_first_search or
# astar_search to have no duplicated states, so we treat nodes
# with the same state as equal. [Problem: this may not be what you
# want in other contexts.]
def __eq__(self, other):
return isinstance(other, Node) and self.state == other.state
def __hash__(self):
return hash(str(self.state))
This is the dfs_search code:
def depth_limited_search(self, problem, limit=50):
return self.recursive_dls(Node(problem.initialState()), problem, limit)
def recursive_dls(self, node, problem, limit):
print str(type(node.state)) + "\n"
new_state=node.state
print new_state[1]
if problem.goalTest(node.state):
return node
elif node.depth == limit:
return 'cutoff'
else:
cutoff_occurred = False
for child in node.expand(problem):
result = self.recursive_dls(child, problem, limit)
if result == 'cutoff':
cutoff_occurred = True
elif result is not None:
return result
return if_(cutoff_occurred, 'cutoff', None)
here, node.state type is tuple
which has value ('r',2)
when i say node.state[1]
it gives int' object has no attribute 'getitem'
the above error
please guide here

Python priorityQueue.get() returns int instead of object

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

How to create new class instances dynamically at runtime in python?

I am trying to solve this problem:
Imagine a (literal) stack of plates. If the stack gets too high, it
might topple. There- fore, in real life, we would likely start a new
stack when the previous stack exceeds some threshold. Implement a data
structure SetOfStacks that mimics this. SetOf- Stacks should be
composed of several stacks, and should create a new stack once the
previous one exceeds capacity. SetOfStacks.push() and
SetOfStacks.pop() should behave identically to a single stack (that
is, pop() should return the same values as it would if there were just
a single stack). Bonus: Implement a function popAt(int index) which
performs a pop operation on a specific sub-stack.
So I wrote the code:
#!/bin/env python
from types import *
class Stack:
def __init__(self):
self.items = []
self.capacity = 3
self.stackscount = 0
def create(self):
id = self.stackscount + 1
id = str(id) + "_stack"
# How to create a new instance of Stack class at runtime ?
# the __init__ must be run too.
def push(self, item):
if self.size() <= self.capacity:
self.items.append(item)
else:
self.create()
def pop(self):
return self.items.pop()
def popAt(self):
pass
def peek(self):
return self.items[len(self.items)-1]
def size(self):
return len(self.items)
s = Stack()
s.push(10)
How do I create a new s type object dynamically at runtime? I searched on the internet and found that using new.instance or new.classobj is the solution but when I did so my new object did not seem to have items from __init__ function. In python3, type() seems to be the answer but the docs doesn't have any examples.
You've confused yourself by referring to a "type object". In Python that means the class itself, not its instances.
To create new Stack objects, simply do what you're already doing: call the Stack class. You can append them to a list:
stacks = [Stack() for _ in range(5)]
However, as jon points out, that won't solve your problem since you haven't defined the SetOfStacks class.
You could simply use a parent-child relation : when a Stack is full, it creates a child and delegate next pushes to it. It could lead to :
class Stack:
def __init__(self, parent = None, id=None):
self.stackscount = 0
self.capacity = 3
self.items = []
self.parent = parent
self.id = id
self.child = None
def create(self):
id = self.stackscount + 1
id = str(id) + "_stack"
return Stack(self, id)
def push(self, item):
if self.size() <= self.capacity:
self.items.append(item)
else:
if self.child is None:
self.child = self.create()
self.child.push(item)
def pop(self):
if self.child is not None:
item = self.child.pop()
if len(self.child.items) == 0:
self.child = None
else:
item = self.items.pop()
return item
def popAt(self):
pass
def peek(self):
if self.child is not None:
item = self.child.peek()
else:
item = self.items[len(self.items)-1]
return item
def size(self):
l = len(self.items)
if self.child is not None:
l += self.child.size()
return l
s = Stack()
s.push(10)
popAt is still to be implemented, but I tested it and it correctly creates new stacks when pushing and empties and removes them when popping.
The implementation of popAt will require some evolutions to current pop implementation, to allow removing an intermediate stack :
def pop(self):
if self.child is not None:
item = self.child.pop()
if len(self.child.items) == 0:
self.child = self.child.child
if self.child is not None:
self.child.parent = self
else:
item = self.items.pop()
return item
def popAt(self, stacknumber):
s = self
for i in range(stacknumber):
s = s.child
if s is None:
return None
if len(s.items) == 0:
return None
item = s.items.pop()
if len(s.items) == 0 and s.parent is not None:
s.parent.child = s.child
if s.child is not None:
s.child.parent = s.parent
return item
The type() function is indeed what you are looking for. Documentation can be found here: https://docs.python.org/2/library/functions.html#type
You can call it like this:
# Bases is a tuple of parent classes to inherit
bases = Stack,
# Dict contains extra properties for the class, for example if you want to add a class variable or function
dict_ = {}
# Construct the class
YourClass = type('YourClass', bases, dict_)
# Create an instance of the class
your_instance = YourClass()
It looks like you are just looking at instance creation though:
class Stack(object):
def create(self):
id = self.stackscount + 1
id = str(id) + "_stack"
# How to create a new instance of Stack class at runtime ?
# the __init__ must be run too.
stack = Stack()

Python not returning the same object?

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.

Categories

Resources