Finding a Node in a Tree using recursion in python - python

class Node:
def __init__(self, tree, data, parent=None):
self.data = data
self.parent = parent
self.children = []
self.tree = tree
def find(self, x):
if self.data is x:
return self
elif self.children:
for node in self.children:
return node.find(person)
else:
return None
I am really stuck, i can't seem to create a method in my Node class that finds a Node with data x and returns that Node. If no Node is found, it will return None.

you're searching for parent in children, while you should search for x
class Node():
def __init__(self, tree, data, parent=None):
self.data = data
self.parent = parent
self.children = []
self.tree = tree
def find(self, x):
if self.data is x: return self
for node in self.children:
n = node.find(x)
if n: return n
return None
>>> n = Node(None, 1)
>>> n.children = [Node(None, 2), Node(None, 3)]
>>> print n.find(3).data
3

I think the immediate fix would be to change this
for node in self.children:
return node.find(person)
To this
for node in self.children:
res = node.find(person)
if res is not None:
return res

Related

LinkedList implementation in Python not showing beyond the head node

My attempts at creating a linked list from scratch in Python are not working, and I'm not sure what I am missing. I tried to create separate classes for nodes and linked lists, but when I am trying to see beyond the head node, I hit a road block.
Appreciate any pointers (no pun intended). Also, what is a better approach: have a separate class for the nodes, or make them an attribute of the linked list class itself?
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class LinkedList:
def __init__(self):
self.head = None
# adding/inserting to the tail
def add(self, val):
node_to_add = ListNode()
if self.head == None:
self.head = node_to_add
node_to_add.val = val
else:
self.next = node_to_add
node_to_add.val = val
# printing the linked list as a list
def print(self):
list_to_print = []
if not self.head:
return None
node_to_read = self.head
while self.head:
list_to_print.append(node_to_read.val)
if node_to_read.next:
self.head = node_to_read.next
else:
return list_to_print
When I run this code, I only can print the head node. When I add nodes/values after the first entry, the print() only returns the head.
test1 = LinkedList()
test1.add(1)
test1.add(4)
test1.add(7)
test1.print()
the output is
[1]
In order to append items to the last Node you need to keep track of the last node.
You also should not override your head pointer in the print function.
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class LinkedList:
def __init__(self):
self.head = None
self.tail = None
# adding/inserting to the tail
def add(self, val):
node_to_add = ListNode()
node_to_add.val = val
if self.tail == None:
self.head = node_to_add
self.tail = node_to_add
else:
self.tail.next = node_to_add
self.tail = node_to_add
# printing the linked list as a list
def print(self):
list_to_print = []
if not self.head:
return None
current_node = self.head
while current_node:
list_to_print.append(current_node.val)
if current_node.next:
current_node = current_node.next
else:
return list_to_print
You can simplify this significantly by giving the node responsibility for adding children. This makes the linked list object basically a wrapper that manages the head and iterations over the list:
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def add(self, node):
if self.next is None:
self.next = node
else:
self.next.add(node)
class LinkedList:
def __init__(self):
self.head = None
def add(self, val):
node = ListNode(val)
if self.head == None:
self.head = node
else:
self.head.add(node)
# printing the linked list as a list
def print(self):
list_to_print = []
node_to_read = self.head
while node_to_read:
list_to_print.append(node_to_read.val)
node_to_read = node_to_read.next
print(list_to_print)
test1 = LinkedList()
test1.add(1)
test1.add(4)
test1.add(7)
test1.print()
# [1, 4, 7]

Anytree NodeMixin

I want to use the NodeMixin Module, but it's not really clear to me if I read the documentation how to do that.
https://anytree.readthedocs.io/en/2.8.0/api/anytree.node.html#anytree.node.nodemixin.NodeMixin
I have a BaseClas like this:
from anytree import NodeMixin, RenderTree
class Tree():
def __init__(self, data, parent):
self.data = data
self.parent = parent
self.children = []
def __eq__(self, other):
if isinstance(other, Tree):
return self.data == other.data
else:
return False
def __repr__(self):
return "Tree("+str(self.data)+","+str(self.children)+")"
def __str__(self):
return self.__repr__()
def update_parent(self, new):
self.parent = new
def add_child(self, c):
self.children.append(c)
def rm_child(self, c):
self.children.remove(c)
If I want to use the NodeMixin Module I would need something like this:
class TreeMix(Tree, NodeMixin): # Add Node feature
def __init__(self, name, length, width, parent=None, children=None):
super(TreeMix, self).__init__()
self.name = name
self.length = length
self.width = width
self.parent = parent
if children:
self.children = children
I get this Error Message:
init() missing 2 required positional arguments: 'data' and 'parent'
I create Objects like this:
my0 = TreeMix('0', 0, 0, parent=None)
my1 = TreeMix('1', 1, 0, parent=my0)
my2 = TreeMix('2', 2, 0, parent=my1)
Did I get the Constructor wrong?

Python class iterator

I have a class of the node which contain his parent and want to create iterator on it. Here is my try:
class Node:
def __init__(self, parent=None):
self._parent = parent
def __iter__(self):
self = self.parent
def __next__(self):
if self.parent is None:
raise StopIteration
else:
self = self.parent
return self
But when I try to loop over the instance, it's never stops and returns the same value, what I did wrong?
The reason your code doesn't work is that you're trying to keep track of the current node in the iterator by assigning to self, which is just a local variable, so nothing is actually updated.
The correct way would be to extract an iterator class and keep track of the current node there:
class Node:
def __init__(self, parent=None):
self.parent = parent
def __iter__(self):
return NodeIterator(self)
class NodeIterator:
def __init__(self, node):
self.next_node = node
def __iter__(self):
return self
def __next__(self):
if self.next_node is None:
raise StopIteration
else:
current_node = self.next_node
self.next_node = self.next_node.parent
return current_node
This can be used like so:
root = Node()
inner_1 = Node(root)
leaf_1 = Node(inner_1)
inner_2 = Node(root)
inner_2_1 = Node(inner_2)
leaf_2 = Node(inner_2_1)
for node in leaf_2:
# will loop through:
# leaf_2,
# inner_2_1;
# inner_2,
# root

how to instantiate a class and print the value

hope somebody can give me a hint here - so i have a Node class that should receive 1 mandatory value and one optional one. The idea is to return a linked list
class Node(object):
def __init__(self, value, next_node = None):
self.value = value
self.next_node = next_node
def get_next(self):
return self.next_node
Now i'm using this class to create a linked list like:
Z = Node('Z')
Y = Node('Y', Z)
X = Node('X', Y)
W = Node('W', X)
Now I want to write a function that receives the head of the list and prints it:
def print_reverse(head):
current = head
my_list = []
while current:
current = current.next_node
u = Node(current)
my_list.append(u.value)
print my_list
print_reverse(W)
The problem I'm facing is that i get back the memory address instead of the actual value.
[<__main__.Node object at 0x1033eb390>, <__main__.Node object at 0x1033eb350>, <__main__.Node object at 0x1033eb310>, None]
Basically I don't know how to instantiate the value of the Node. I would want to get back this
[ W, X, Y , Z, None]
class Node(object):
def __init__(self, value, next_node = None):
self.value = value
self.next_node = next_node
def get_next(self):
return self.next_node
def print_reverse(head):
current = head
my_list = []
my_list.append(current.value)
while current.next_node != None:
current = current.next_node
my_list.append(current.value)
print my_list
Z = Node('Z')
Y = Node('Y', Z)
X = Node('X', Y)
W = Node('W', X)
print_reverse(W)
This runs and prints ['W','X','Y','Z'] for me.
You need implement repr which should return a printable representation of the object. eg.
class Node(object):
def __init__(self, value, next_node = None):
self.value = value
self.next_node = next_node
def get_next(self):
return self.next_node
def __repr__(self):
return self.value
https://docs.python.org/2/reference/datamodel.html#object.repr

Python Linked List with Nodes. Iterable

I need some help writing an __iter__() method for my UnorderedList() class. I tried this:
def __iter__(self):
current = self
while current != None:
yield current
But the while loop doesn't stop. Here is the rest of my classes and code:
class Node:
def __init__(self,initdata):
self.data = initdata
self.next = None
def getData(self):
return self.data
def getNext(self):
return self.next
def setData(self,newdata):
self.data = newdata
def setNext(self,newnext):
self.next = newnext
class UnorderedList:
def __init__(self):
self.head = None
self.count = 0
If you want to iterate all items succeedingly, you should do
def __iter__(self):
# Remember, self is our UnorderedList.
# In order to get to the first Node, we must do
current = self.head
# and then, until we have reached the end:
while current is not None:
yield current
# in order to get from one Node to the next one:
current = current.next
so that in every step you go one step further.
BTW, setters and getters aren't used in Python in the form of methods. If you need them, use properties, otherwise omit them altogether.
So just do
class Node(object):
def __init__(self, initdata):
self.data = initdata
self.next = None
class UnorderedList(object):
def __init__(self):
self.head = None
self.count = 0
def __iter__(self):
current = self.head
while current is not None:
yield current
current = current.next

Categories