Fix depth tree in Python - python

I want to implement a tree structure which has fixed depth, i.e. when adding children to the leef nodes, the whole tree structure should "move up". This also means that several roots can exist simultaneously. See example beneath:
In this example, the green nodes are added in iteration 1, deleting the top node (grey) and making the two blue nodes at K=0 and Iteration 1 root nodes.
How do I go about implementing this?

Store each node with a reference to its parent. When you add a node to it as a child, walk up the parents (from the node being added to) and delete the third one after you set the parent reference in all of its children to None. Then add the children of the deleted node to your list of trees.
class Node(object):
depth = 4
def __init__(self, parent, contents):
self.parent = parent
self.contents = contents
self.children = []
def create_node(trees, parent, contents):
"""Adds a leaf to a specified node in the set of trees.
Note that it has to have access to the container that holds all of the trees so
that it can delete the appropriate parent node and add its children as independent
trees. Passing it in seems a little ugly. The container of trees could be a class
with this as a method or you could use a global list. Or something completely
different. The important thing is that if you don't delete every reference to the
old root, you'll leak memory.
"""
parent.children.append(Node(parent, contents))
i = 0:
L = Node.depth - 1
while i < L:
parent = parent.parent
if not parent:
break
i += 1
else:
for node in parent.children:
node.parent = None
trees.extend(parent.children)
i = trees.find(parent)
del trees[i]

Related

python linked structure - inserting child to node A's parent is also inserting to node A

I'm trying to implement a linked structure for a tree using python
this is an extract of my code
class Node(object):
def __init__(self,value,father=None,children=[]):
self.value=value
self.father=father
self.children=children
def __str__(self):
return self.value
class Tree(object):
def __init__(self,root=None):
self.root=root
def insertNode(self,new_node,father_value):
father_node=self.find_node(father_value)
if not father_node:
return False
new_node.father=father_node
print("Node's information BEFORE adding child to father's list of children")
print(f"Father node (find) {father_node}")
print(f"Father node's children {[x.value for x in father_node.children]}")
print(f"New node's father {new_node.father}")
print(f"New node's children {[x.value for x in new_node.children]}")
father_node.children.append(new_node)
print("Node's information AFTER adding child to father's list of children")
print(f"Father node (find) {father_node}")
print(f"Father node's children {[x.value for x in father_node.children]}")
print(f"New node's father {new_node.father}")
print(f"New node's children {[x.value for x in new_node.children]}")
def find_node(self,value):
stack=[self.root]
while True:
if len(stack)==0:
return False
node=stack.pop()
if node.value==value:
return node
children=node.children
stack.extend(children)
n1=Node("A")
tree=Tree(n1)
tree.insertNode(Node("B"),"A")
n1=Node("A")
tree=Tree(n1)
tree.insertNode(Node("B"),"A")
the OUTPUT is
Node's information BEFORE adding child to father's list of children
Father node (find) A
Father node's children []
New node's father A
New node's children []
Node's information AFTER adding child to father's list of children
Father node (find) A
Father node's children ['B']
New node's father A
New node's children ['B']
As you can see, when I append the new inserted node into the father's children list it also inserts into the new node's list of children. How to fix this?
The problem occurs because of how Python deals with default values of optional parameters of a function.
In class Node(object), you have this line:
def __init__(self,value,father=None,children=[]):
Python evaluates the default value [] only once (creating an empty list object), and then reuses that evaluated value (reference to that list object) for all subsequent invocations of that function.
In your case the function is the __init__() function, which gets invoked each time you instantiate the Node class. If you instantiate Node multiple times without explicitly passing in a third argument, in all those invocations of __init__(), the parameter children gets assigned the same list object as the default value. You are using this value to set the children attribute of all these instances. In other words, for all those Node instances, the children attribute would be pointing to the same list object. That is why inserting a child to the "father" Node is also adding the same child to the current Node.
The correct way to re-write __init__() would be:
class Node(object):
def __init__(self,value,father=None,children=None):
self.value=value
self.father=father
self.children=children if children is not None else []
Moral
The general moral here is that, if your parameter's default value is a mutable object, it can throw surprises like this -- where, unknown to you, multiple references are stored to a single object, and mutations (changes) to the object through one reference, will also get reflected (seen) through the other references.
This is all documented here

In Python, why does .append give different results than using +? [duplicate]

This question already has answers here:
Why does using `arg=None` fix Python's mutable default argument issue?
(5 answers)
Closed 3 years ago.
I want to implement a very simple tree data structure in Python.
I want to make it so that everytime I add a new node and I specify its parent, then it is automatically added to the children attribute of its parent.
I have two different ways to do it, one works and one doesn't but I don't understand why.
class Node():
def __init__(self, value, parent = None, children = []):
self.value = value #This is for us to see the name
self.parent = parent #Parent node
self.children = children #List of child nodes
#Set this Node as a children of its own parent
if not parent == None:
#self.parent.children.append(self) <--- wrong code
self.parent.children = self.parent.children + [self]
def __repr__(self):
return str(self.value)
tree = Node("tree")
branch1 = Node("branch1", parent = tree)
branch2 = Node("branch2", parent = tree)
leaf = Node("leaf", parent = branch1)
Here is what I get with the code as is and what I would get if I replace the last line of __init__ with the commentated line.
print(tree.children)
#[branch1, branch2] <--- expected
#[branch1, branch2, leaf] <--- with wrong code
print(branch1.children)
#[leaf] <--- expected
#[branch1, branch2, leaf] <--- with wrong code
Using the .append method adds the node not only to the list children of its parent but to everybody. Even if I define a new Node("other") completely detached from the others. Why is that?
The problem is in the use of mutable default value:
def __init__(self, value, parent = None, children = []):
The empty list [] gets created only once, when the function is defined, and all invocations share the same list! This is why append to one list of children modifies all of them - because they all are one and the same list object. When you use + to append to the list, you work around the above bug because you re-create the list every time, thus unsharing the children objects.
The correct solution is to replace children=[] with something like:
def __init__(self, value, parent=None, children=None):
if children is None:
children = []
That will guarantee the creation of a new list for children, and then append and + should have the same result.

Recursive loop not having expected behavior

So I create a tree in python. I am trying to change some value of every child of the root node. But, every node in my tree is not being hit.
class Node(object):
def __init__(self, value, priority):
self.parent = None
self.children = []
self.value = value
self.priority = priority
def add_child(self, obj):
self.children.insert(obj)
obj.parent = self
def getChildren(self):
return self.children.getAll()
tom = Node("DD",1)
tom.add_child(Node("a",0.3))
tom.add_child (Node("b", 0.6))
tom.getChildren()[0].add_child(Node("c",1))
tom.getChildren()[1].add_child(Node("d",1))
#print(tom.popHighestValue().value)
def getAll(currentNode):
print(currentNode.value)
if(currentNode.getChildren != []):
for sibling in currentNode.getChildren():
sibling.priority = 1
return getAll(sibling)
The tree should look like:
DD
/\
a b
/
c
But only DD->a->c are being hit. I thought the for loop state would be saved and continued after DD -> c was traversed.
The goal is that every node in the tree is hit. And the priority value is set to 1.
A return statement always exits the current function. If you're in a loop when you do this, the rest of the loop is never executed.
If you need to return all the values of the recursive calls, you need to collect them in a list during the loop, then return that list after the loop is done.
But in this case there doesn't seem to be anything you need to return. This function is just for setting an attribute, there's nothing being extracted. So just make the recursive call without returning.
def getAll(currentNode):
print(currentNode.value)
for sibling in currentNode.getChildren():
sibling.priority = 1
getAll(sibling)
BTW, this won't set the priority of the root node, since it only sets the priority of children. If you want to include the root node, it should be:
def getAll(currentNode):
print(currentNode.value)
currentNode.priority = 1
for sibling in currentNode.getChildren():
getAll(sibling)
Also, you shouldn't call getAll() in the getChildren() method. It just return self.children, not self.children.getAll().
If you remove the return before calling getAll() and place it outside the enclosing for loop, that would fix your problem.
In your code, you are unable to process all the children because right after your first iteration you call getAll() with the return statement. So, all the other siblings except first are/will not be explored at every depth.

Implementing a (modified) DFS in a Graph

I have implemented a simple graph data structure in Python with the following structure below. The code is here just to clarify what the functions/variables mean, but they are pretty self-explanatory so you can skip reading it.
class Node:
def __init__(self, label):
self.out_edges = []
self.label = label
self.is_goal = False
self.is_visited = False
def add_edge(self, node, weight):
self.out_edges.append(Edge(node, weight))
def visit(self):
self.is_visited = True
class Edge:
def __init__(self, node, weight):
self.node = node
self.weight = weight
def to(self):
return self.node
class Graph:
def __init__(self):
self.nodes = []
def add_node(self, label):
self.nodes.append(Node(label))
def visit_nodes(self):
for node in self.nodes:
node.is_visited = True
Now I am trying to implement a depth-first search which starts from a given node v, and returns a path (in list form) to a goal node. By goal node, I mean a node with the attribute is_goal set to true. If a path exists, and a goal node is found, the string ':-)' is added to the list. Otherwise, the function just performs a DFS and goes as far as it can go. (I do this here just to easily check whether a path exists or not).
This is my implementation:
def dfs(G, v):
path = [] # path is empty so far
v.visit() # mark the node as visited
path.append(v.label) # add to path
if v.is_goal: # if v is a goal node
path.append(':-)') # indicate a path is reached
G.visit_nodes() # set all remaining nodes to visited
else:
for edge in v.out_edges: # for each out_edge of the starting node
if not edge.to().is_visited: # if the node pointed to is not visited
path += dfs(G, edge.to()) # return the path + dfs starting from that node
return path
Now the problem is, I have to set all the nodes to visited (line 9, visit_nodes()) for the algorithm to end once a goal node is reached. In effect, this sort of breaks out of the awaiting recursive calls since it ensures no other nodes are added to the path. My question is:
Is there a cleaner/better way to do this?
The solution seems a bit kludgy. I'd appreciate any help.
It would be better not to clutter the graph structure with visited information, as that really is context-sensitive information linked to a search algorithm, not with the graph itself. You can use a separate set instead.
Secondly, you have a bug in the code, as you keep adding to the path variable, even if your recursive call did not find the target node. So your path will even have nodes in sequence that have no edge between them, but are (close or remote) siblings/cousins.
Instead you should only return a path when you found the target node, and then after making the recursive call you should test that condition to determine whether to prefix that path with the current edge node you are trying with.
There is in fact no need to keep a path variable, as per recursion level you are only looking for one node to be added to a path you get from the recursive call. It is not necessary to store that one node in a list. Just a simple variable will do.
Here is the suggested code (not tested):
def dfs(G, v):
visited = set() # keep visited information away from graph
def _dfs(v):
visited.add(v) # mark the node as visited
if v.is_goal:
return [':-)'] # return end point of path
for edge in v.out_edges:
neighbor = edge.to() # to avoid calling to() several times
if neighbor not in visited:
result = _dfs(neighbor)
if result: # only when successful
# we only need 1 success: add current neighbor and exit
return [neighbor.label] + result
# otherwise, nothing should change to any path: continue
# don't return anything in case of failure
# call nested function: the visited and Graph variables are shared
return _dfs(v)
Remark
For the same reason as for visited, it is maybe better to remove the is_goal marking from the graph as well, and pass that target node as an additional argument to the dfs function.
It would also be nice to give a default value for the weight argument, so that you can use this code for unweighted graphs as well.
See how it runs on a sample graph with 5 nodes on repl.it.

Update parent pointers in a binary tree

The question is, given a binary tree, where each node has four pieces of data: left, right ,data and an empty pointer parent, we have to update the tree such that the parent pointer of each node points to its parent (the root parent pointer will naturally point to a NULL value). Now how do I do this? I tried a post-order traversal like this:
last = None
def mypostorder(root):
if root:
mypostorder(root.left)
mypostorder(root.right)
if last:
last.parent = root
last = root
But obviously it is not working, and I know why, after updating the parent pointer of a left-child, it sets it as last, so next time when it visits the right-child (its sibling), it sets its parent to the left-child. How to tweak it to get the correct result? Is it possible to do it iteratively as well, using a stack, may be?
void setParent(node * ptr,node * parent_ptr)
{
if(ptr==NULL)
return;
ptr->parent=parent_ptr; //update the parent for the current node
parent_ptr=ptr; //now update the parent pointer
setParent(ptr->left,parent_ptr); //repeat the process for children
setParent(ptr->right,parent_ptr);
}
Initial Call : setParent(root,NULL);
You have it going the wrong way. I think your solution would make the parent of a node point to its child
Give this a try:
def myPostOrder(root, par=None):
if root:
root.parent = par
myPostOrder(root.left, root)
myPostOrder(root.right, root)

Categories

Resources