Sum of all nodes of a Binary Tree - python

I'm trying to write a program to calculate the sum of all nodes (including the root) in a Binary Tree (not a Binary Search Tree) represented by a list of lists. I conceptually understand that approaching this recursively is the best way to do it but just cannot figure out the code. So far, my code is:
class BinaryTree:
def __init__(self,rootObj, leftChild = None, rightChild = None):
self.key = rootObj
self.leftChild = None
self.rightChild = None
self.node=[rootObj, leftChild, rightChild]
def getrightChild(self):
return self.rightChild
def getleftChild(self):
return self.leftChild
def setRootObj(self,obj):
self.key = obj
def getRootObj(self):
return self.key
def sumTree(BinaryTree):
if BinaryTree is None: return 0
return sumTree(BinaryTree.leftChild) \
+ sumTree(BinaryTree.rightChild)\
+ BinaryTree.rootObj
print(sumTree([8,[],[]]))
print(sumTree([9, [6, [ ], [ ]], [65, [ ], [ ]]]))

Be careful,
self.key = rootObj
self.leftChild = None
self.rightChild = None
are object attributes, so you can't access them with through your class directly. You have to create an instance like
obj = BinaryTree(...)
and then call the method
obj.sumTree(...)
To your sum algorithm, the easiest way to calculate the sum your way would be something like this:
class BinaryTree:
#classmethod
def calc_sum(cls, list_tree):
print(list_tree)
if list_tree:
left_node_value = BinaryTree.calc_sum(list_tree[1])
right_node_value = BinaryTree.calc_sum(list_tree[2])
return list_tree[0] + left_node_value + right_node_value
return 0
value = BinaryTree.calc_sum([9, [6, [ ], [ ]], [65, [ ], [ ]]])
print(value)

You don't need all the getters. You can simply use object accessor methods, e.g. tree_a.left_child. Secondly, you didn't create a BinaryTree out of your children, meaning that it doesn't make sense to run sum_tree on them. Read through the following code, and make sure that you understand what's going on.
Pretty sure that what you actually want, is this
class BinaryTree:
def __init__(self, root, left_child=None, right_child=None):
self.root = root
self.left_child = None if not left_child else BinaryTree(*left_child)
self.right_child = None if not right_child else BinaryTree(*right_child)
self.node = [root, left_child, right_child]
def set_root(self, root):
self.root = root
def sum_tree(self):
tree_sum = 0
if self.left_child:
tree_sum += self.left_child.sum_tree()
if self.right_child:
tree_sum += self.right_child.sum_tree()
return tree_sum + self.root
tree_a = BinaryTree(8)
tree_b = BinaryTree(9, [6, [], []], [65, [], []])
print(tree_a.sum_tree())
# 8
print(tree_b.sum_tree())
# 80
print(tree_b.left_child.node)
# [6, [], []]

Well, from what I read from this code, your recursive algorithm is correct.
However, there are many syntax mistakes as well as other, semantic mistakes in it that make it impossible to run correctly.
Here is what I see:
You created a BinaryTree class, but you never created an instance of it.
sumTree([...]) tries to calculate that sum of a list, which will not work, because you want it to do it for a BinaryTree object. You need to parse that list and create an instance of BinaryTree first. (Like tree = BinaryTree(*write your list here*) maybe. But you need to make your __init__() method allow that passing of the list, of course. See next point.)
Your __init__() method takes BinaryTree objects as parameters, so there is no parsing of your lists.
Within the __init__() method, you set both children to None, so no node will ever have child nodes.
When calling the sumTree() method, you need to specify the context.
It needs to be BinaryTree.sumTree(..). You still need to create the Binary tree instance that shall be passed to the sumTree method, though.
Within the sumTree() method, you try to access the rootObj member - which does not exist, because you called it key.
Besides the errors, I'd like to point out some "code smells", if you like.
You should rename the parameter of the sumTree() method to something different ot the class name.
In python, there is no need for Getter-methods. You can access the members directly. If you still wish to define more complex get/set behaviour, you should have a look at python properties.
The member node is never used.

Related

Stack data structure in Python using lists

For the stack class below
class stack(list):
def __init__(self):
self.stack = []
self.top = -1
def isempty(self):
return self.stack == []
def push(self,x):
S.top = S.top + 1
return self.stack.append(x)
S = stack()
S.isempty() #True
S.push(5) #[5]
S.push(100) #[5,100]
print(S) # Returns empty stack []
Why does it not return the updated [5,100]?
The problem that you're asking about is that you're inheriting from list, even though you're not trying to act like a list. All this is doing is causing confusion. In particular, you're letting the list superclass define how your objects get displayed, and since you never do anything like self.append, only self.stack.append, that means it's always going to display like an empty list.
Once you fix that, your objects will always print something like this:
<__main__.stack at 0x11d919dd8>
If you want to customize that, you need to write a __repr__ method, and decide what you want it to look like.
class stack:
def __init__(self):
self.stack = []
self.top = -1
def __repr__(self):
return f'<stack({self.stack})>'
def isempty(self):
return self.stack == []
def push(self,x):
S.top = S.top + 1
return self.stack.append(x)
There are additional bugs in your code—you've still got a method that mutates the global S instead of self, and you're returning the result of list.append, which always returns None, and maybe more beyond—but these two changes will together solve the specific problem you're asking about.

How to create a specific Binary Tree?

I have just implemented my first Binary Tree:
class BinaryTree:
def __init__(self, obj):
self.key = obj
self.left_c = None
self.right_c = None
def insert_left_c(self, new_node):
if self.left_c == None:
self.left_c = BinaryTree(new_node)
else:
temp = BinaryTree(new_code)
temp.left_c = self.left_c
self.left_c = temp
def insert_right_c(self, new_node):
if self.right_c == None:
self.right_c = BinaryTree(new_node)
else:
temp = BinaryTree(new_code)
temp.right_c = self.right_c
self.right_c = temp
def set_root(self, obj):
self.key = obj
def get_root(self):
return self.key
def get_left_c(self):
return self.left_c
def get_right_c(self):
return self.right_c
I am struggling to understand how you actually go about building a tree to ones specifications. As an example, I am trying to build the following tree:
However, I am really struggling to understand / visualize how you build the lower nodes and manipulate their left / right branches.
I though I may be able to do something such as:
binary_tree = BinaryTree('a')
binary_tree.insert_left_c('b')
binary_tree.insert_right_c('d')
binary_tree.insert_right_c('c')
binary_tree.insert_left_c('e')
binary_tree.insert_right_c('f')
But I realize that is nonsensical because I believe I'm creating a unique node for all letters that would be on the same level? I never actually set one to be a child of another(?).
If someone could explain how one should go about solving this, and visualizing similar problems, I would much appreciate it.
Your insert functions only operate on the root, without traversing deeper into the tree. Usually, such a function would insert into a binary search tree, recursing left or right depending on how the value to insert compares to the root of the current tree. For a general binary tree, you would want to pass an explicit list of left/right directions to specify where a new value goes.
It would be simpler to just build the tree explicitly. Start with individual trees for each leaf, then merge them.
trees = {x: BinaryTree(x) for x in 'abcdef'}
binary_tree = trees['a']
binary_tree.left_c = trees['b']
binary_tree.right_c = trees['c']
trees['b'].right_c = trees['d']
trees['c'].left_c = trees['e']
trees['c'].right_c = trees['f']

Weird thing in python classes ?

I was trying to implement a shortest path algorithm in python. I ran into some trouble when I attempted to connect my points on the path.
I have a class called NODE
I made an array of these nodes and then created new nodes in them like this:
nodes = []
for r in range ( 0, 3 ):
for c in range ( 0, 3 ):
nodes.append( NODE( c*WIDTH/20 + 30, r*HEIGHT/20 + 30, 10 ) )
This created nodes, which is fine, I can draw them just fine.
At first I attempted connecting them by adding a list of node objects into the the NODE class. I ran into some issues, I thought the problem is with the recursive classes, so to test I did this. Where connections is a blank array within the NODE class.
nodes[0].connections.append( 0 )
print nodes[0].connections
nodes[1].connections.append( 1 )
print nodes[1].connections
print nodes[0].connections
This is where I found the problem, Maybe I'm just being stupid, or It's a language thing ? Dunno, but I thought I'd ask.
The output is this:
[ 0 ]
[ 0, 1 ]
[ 0, 1 ]
As you can see, I only added 1 object to the connections list in the index 1. However when I print the contents, I see two.... And this confuses me.
Possibilty 1: your code looks like this:
class NODE:
connections = []
def __init__(self, value):
self.value = value
nodes = [NODE(23), NODE(42)]
nodes[0].connections.append( 0 )
print nodes[0].connections
nodes[1].connections.append( 1 )
print nodes[1].connections
print nodes[0].connections
Solution: class instance attributes should be defined inside __init__. If you define connections at the class level, then every single instance of NODE will share the same one connections list.
class NODE:
def __init__(self, value):
self.value = value
self.connections = []
Possibility 2: your code looks like this:
class NODE:
def __init__(self, value, connections = []):
self.value = value
self.connections = connections
nodes = [NODE(23), NODE(42)]
nodes[0].connections.append( 0 )
print nodes[0].connections
nodes[1].connections.append( 1 )
print nodes[1].connections
print nodes[0].connections
Solution: the default value in an argument list is created only once, so all instances of NODE using that default value will share the same one list. use a non-mutable sentinel value to indicate that no argument was passed. None is usually suitable for this task.
class NODE:
def __init__(self, value, connections = None):
self.value = value
if connections is not None:
self.connections = connections
else:
self.connections = []

TypeError: 'node' object is not callable

I am getting an error (TypeError: 'node' object is not callable) when I try to get my previous node. What am I doing wrong?
My Node Class:
class node(object):
def __init__(self):
self.node=[]
self.info = None
self.prev = None
self.depth=-1
self.step = []
def prev(self):
return self.prev
def add(self):
node1=node()
self.node.append(node1)
node1.prev=self
return node1
My Code accessing prev (last_node should have a depth value of around 5):
rev = last_node
dep = rev.depth
revPath = [None]*(dep*4)
for g in range(0,dep):
revPath[dep - (g*4) - 1] = rev.step[3]
revPath[dep - (g*4) - 2] = rev.step[2]
revPath[dep - (g*4) - 3] = rev.step[1]
revPath[dep - (g*4) - 4] = rev.step[0]
rev = rev.prev()
Additional info:
I am trying to traverse the tree backwards in order to see the path that was taken. The step[] value just grabs a few integers. The code also runs fine with everything except prev (i.e. If I take out the part to find the path taken, there is no issue).
You've defined a method called prev in your class, but in your constructor you assign None to self.prev, and then later in add you assign to it again with a node instance.
Therefore, when you try to invoke rev.prev(), the method has been over-written and you're in fact trying to call a node object, hence the error.
It's conventional in Python (see PEP-0008) to prefix private fields (those that client code is not supposed to use) with an underscore, like so:
def __init__(self):
self._node=[]
self._prev = None
# Etc.
It's also risky to name your class in lower case, since any variable named node will shadow it and make it inaccessible. The convention in Python is to use Pascal casing (starting with a capital) for class names (see PEP-0008 again).

Implementing a depth-first tree iterator in Python

I'm trying to implement an iterator class for not-necessarily-binary trees in Python. After the iterator is constructed with a tree's root node, its next() function can be called repeatedly to traverse the tree in depth-first order (e.g., this order), finally returning None when there are no nodes left.
Here is the basic Node class for a tree:
class Node(object):
def __init__(self, title, children=None):
self.title = title
self.children = children or []
self.visited = False
def __str__(self):
return self.title
As you can see above, I introduced a visited property to the nodes for my first approach, since I didn't see a way around it. With that extra measure of state, the Iterator class looks like this:
class Iterator(object):
def __init__(self, root):
self.stack = []
self.current = root
def next(self):
if self.current is None:
return None
self.stack.append(self.current)
self.current.visited = True
# Root case
if len(self.stack) == 1:
return self.current
while self.stack:
self.current = self.stack[-1]
for child in self.current.children:
if not child.visited:
self.current = child
return child
self.stack.pop()
This is all well and good, but I want to get rid of the need for the visited property, without resorting to recursion or any other alterations to the Node class.
All the state I need should be taken care of in the iterator, but I'm at a loss about how that can be done. Keeping a visited list for the whole tree is non-scalable and out of the question, so there must be a clever way to use the stack.
What especially confuses me is this--since the next() function, of course, returns, how can I remember where I've been without marking anything or using excess storage? Intuitively, I think of looping over children, but that logic is broken/forgotten when the next() function returns!
UPDATE - Here is a small test:
tree = Node(
'A', [
Node('B', [
Node('C', [
Node('D')
]),
Node('E'),
]),
Node('F'),
Node('G'),
])
iter = Iterator(tree)
out = object()
while out:
out = iter.next()
print out
If you really must avoid recursion, this iterator works:
from collections import deque
def node_depth_first_iter(node):
stack = deque([node])
while stack:
# Pop out the first element in the stack
node = stack.popleft()
yield node
# push children onto the front of the stack.
# Note that with a deque.extendleft, the first on in is the last
# one out, so we need to push them in reverse order.
stack.extendleft(reversed(node.children))
With that said, I think that you're thinking about this too hard. A good-ole' (recursive) generator also does the trick:
class Node(object):
def __init__(self, title, children=None):
self.title = title
self.children = children or []
def __str__(self):
return self.title
def __iter__(self):
yield self
for child in self.children:
for node in child:
yield node
both of these pass your tests:
expected = ['A', 'B', 'C', 'D', 'E', 'F', 'G']
# Test recursive generator using Node.__iter__
assert [str(n) for n in tree] == expected
# test non-recursive Iterator
assert [str(n) for n in node_depth_first_iter(tree)] == expected
and you can easily make Node.__iter__ use the non-recursive form if you prefer:
def __iter__(self):
return node_depth_first_iter(self)
That could still potentially hold every label, though. I want the
iterator to keep only a subset of the tree at a time.
But you already are holding everything. Remember that an object is essentially a dictionary with an entry for each attribute. Having self.visited = False in the __init__ of Node means you are storing a redundant "visited" key and False value for every single Node object no matter what. A set, at least, also has the potential of not holding every single node ID. Try this:
class Iterator(object):
def __init__(self, root):
self.visited_ids = set()
...
def next(self):
...
#self.current.visited = True
self.visited_ids.add(id(self.current))
...
#if not child.visited:
if id(child) not in self.visited_ids:
Looking up the ID in the set should be just as fast as accessing a node's attribute. The only way this can be more wasteful than your solution is the overhead of the set object itself (not its elements), which is only a concern if you have multiple concurrent iterators (which you obviously don't, otherwise the node visited attribute couldn't be useful to you).

Categories