I have a a binary tree, with only self._root and self._nodes. Is there anyway I could figure out how to find a parent tree of the current tree through the constructor?
class BinaryTree:
"""
- If _root is None, then _nodes is empty and _parent_tree is None
- nodes is allowed to contain empty nodes
- if _parent_tree is not empty, then self is in _parent_tree._nodes
"""
def __init__(self, root, nodes):
"""Initialize a new BinaryTree.
#type self: BinaryTree
#type root: object
#type nodes: list[BinaryTree]
#rtype: None
"""
self._root = root
self._nodes = nodes
self._parent_tree = None
"""Implement _parent_tree"""
if self._root is not None:
"""implement"""
else:
pass
To be honest, I have no idea of how to even start this. How would I know any other BinaryTree objects without constructing this one first. What would I be recursively looking through? I can't possibly look through this BinaryTree
Following should do good for you :
class BinaryTree:
def __init__(self, root, nodes):
self._root = root
self._nodes = nodes
self._parent_tree = None
if self._root is not None:
for node in self._nodes:
if node is not None:
node._parent_tree = self
else:
pass
Related
So I am running into some issue that has left me dumbfounded. I do not understand where I am going wrong with my code but the idea I have is I check if the current node I am at is None and if it is then I return a list of my tree in in order, pre order, and post order. Here is my code:
class Node:
def __init__(self, data):
self.data = data
self.left = None
self.right = None
def inOrder(self, arr=[]):
if self is not None:
self.left.inOrder(arr)
arr.append(self.data)
self.right.inOrder(arr)
return arr
When I run it I get an error of self.left.inOrder() AttributeError: 'NoneType' object has no attribute 'inOrder' which I have not idea as to why. I am checking that self is not None so shouldn't this guarantee my Node to have a left and right.
I am only showing the inOrder I have implemented.
I have solved this instead by doing the following
class Node:
def __init__(self, data):
self.data = data
self.left = None
self.right = None
def inOrder(self):
if self is not None and self.left is not None:
self.left.inOrder()
print(self.data)
if self is not None and self.right is not None:
self.right.inOrder()
root = Node(1)
root.left = Node(2)
root.right = Node(3)
root.inOrder()
Whether I save it to a list or just print it is fine with me but if I already check if self is not None then shouldn't I be able to call self.left.inOrder and self.right.inOrder?
self is not None. self refers to an instance of the class. self.left is an instance attribute that you set to None in your __init__() method when you create the instance. Because self.left refers to None and the object None does not have the inOrder() method, you obtain an AttributeError. Within your class definition, self (referring to an instance of the class) does have the inOrder() method, but it's attribute self.left (referring to None), does not.
For example if I have 2 classes Tree and Node, in the add_node method in Tree, I can add self referring to the Tree into the Node object as shown below. This is done for convenience when accessing other parts of the Tree with just the keys once in the Node object (i.e. can just use keys). However, I was wondering if this was considered best practice since the IDE (PyCharm) also screams Unresolved attribute reference 'tree' for class 'Node' so might be not a great sign as well.
class Tree:
def __init__(self):
self.nodes = {}
def add_node(self, count):
new_node = Node()
new_node.tree = self
self.nodes[count] = new_node
class Node:
def __init__(self):
# Some data e.g. parent, children index
pass
Pass the tree in the initializer for the Node
class Node:
def __init__(self, tree):
self.tree = tree
And when creating the node:
...
new_node = Node(self)
self.nodes[count] = new_node
...
I was doing this leetcode question:(https://leetcode.com/problems/binary-tree-inorder-traversal/) in which I came up with this solution:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def inorderTraversal(self, root: TreeNode) -> List[int]:
if root is None:
return None
result = []
if root.left is None and root.right is None:
result.append(root.val)
return result
return self.traverse(root,result)
def traverse(self,node,result):
if node is None:
return result
result = self.traverse(node.left,result)
result.append(node.val)
result = self.traverse(node.right,result)
return result
However I found out I actually don't need to store the results of recursion call in the variable and I can simply do this:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def inorderTraversal(self, root: TreeNode) -> List[int]:
if root is None:
return None
result = []
if root.left is None and root.right is None:
result.append(root.val)
return result
return self.traverse(root,result)
def traverse(self,node,result):
if node is None:
return result
self.traverse(node.left,result)
result.append(node.val)
self.traverse(node.right,result)
return result
My understanding was that in each recursion call, we are passing a reference to the result variable, not copying the result variable, so what is happening is that when the recursion call gets to the left most node, it appends the value and returns to its parent node, and since we had pass by reference, the result variable in parent node already has the leftmost node added to it, so it just adds the parent node to it and keep continuing on the recursion.
Is my understanding correct or is there something else going on?
Thanks
Yes, your understanding is right.
Note: you are sharing the same code in both boxes.
Inside a recursive class function, how do i use a class member as default argument?
I am currently using following snippet that works (python 3). height is recursive class function. Default argument that i want to use for node is self._root. In order to achieve this, i do something like following but thats a very round about way where i have to define another function height_tree. Is there a more direct approach?
# following code works #
class BTree:
def __init__(self, node=None):
self._root = node
def height_tree(self):
return self.height(self._root)
def height(self, node):
if node is not None:
height = max(self.height(node.get_left()), self.height(node.get_right())) + 1
else:
height = 0
return height
I want to do something like following but it obviously doesn't works !
def height(self, node=self._root)
# code from above follows
I however cannot use alternate trick of assigning root to node when node is None since that is one of the end condition in recursion
def height(self, node)
if node is None:
node = self._root
# this will conflict with logic in code block above#
Are there any recommended ways to handle such a situation?
You can use a sentinel object:
sentinel = object()
def height(self, node=sentinel)
if node is sentinel:
node = self._root
...
Since such object would have a unique memory address, it would never be identical to any other object (including None).
You can always create arbitrary sentinels:
SENTINEL = object()
class BTree:
def __init__(self, node=None):
self._root = node
def height_tree(self):
return self.height(self._root)
def height(self, node=SENTINEL):
if node is SENTINEL:
node = self._root
elif node is not None:
height = max(self.height(node.get_left()), self.height(node.get_right())) + 1
else:
height = 0
return height
tree = Node ("one",
Node ("two", Leaf ("three"), Leaf ("four")),
Node ("five", Leaf ("six"), Leaf ("seven")))
Trying to declare a Tree class with 2 subclasses Node and Leaf to handle the tree object
class Tree:
def __init__(self, root):
self.root = root
# some functions
#def inorder(self, visitor):
# Node.inorder(self.left, visitor)
# visitor(self.data)
# Node.inorder(self.right, visitor)
#def fns(tree):
# return
class Node (Tree):
def __init__(self, value, left, right):
self.left = left
self.right = right
self.value = value
class Leaf (Tree):
def __init__(self, value):
self.value = value
Would this be the correct implementation?
This would be a correct implementation of binary tree. But keep in mind one thing, if you ever change root of the tree you will need to update every single node and leaf in that tree.
self.root is a bad idea in case you would create subtrees which you would later add to another tree. But if you are not planning to do something like this this would be a good idea.