I'm trying to implement an iterative inorder traversal of a binary tree.
node.py:
class Node:
def __init__(self, node=None, left=None, right=None):
self.node = node
self.left = left
self.right = right
inorder_traversal.py:
from node import Node
def in_order(root):
stack = nodes = []
while stack or root:
if root:
stack.append(root)
root = root.left
else:
current = stack.pop()
nodes.append(current.node)
root = current.right
return nodes
def main():
'''
Construct the below binary tree:
15
/ \
/ \
/ \
10 20
/ \ / \
8 12 16 25
'''
root = Node(15)
root.left = Node(10)
root.right = Node(20)
root.left.left = Node(8)
root.left.right = Node(12)
root.right.left = Node(16)
root.right.right = Node(25)
print(in_order(root))
if __name__ == '__main__':
main()
I've been getting: AttributeError: 'int' object has no attribute 'node'.
How can I resolve this error?
stack = nodes = [] creates two references to the same list object.
When you do stack.append(root) or nodes.append(current.node) this affects both stack and nodes because they are the same. What you want is 2 different objects:
stack = []
nodes = []
Then you'll get this output: [8, 10, 12, 15, 16, 20, 25]
The value of the node variable is initialized to an Int in your code (e.g. Node(5)) and your in_order method push that value on the stack and later pop it and try to access its node variable, which will result in the error.
Here's an implementation that does not have that error and uses recursion for the in order traversal (which can be simpler to follow).
class Node:
def __init__(self, value, left=None, right=None):
self.value = value
self.left = left
self.right = right
def in_order(node):
nodes = []
if node.left:
nodes.extend(in_order(node.left))
nodes.append(node.value)
if node.right:
nodes.extend(in_order(node.right))
return nodes
Related
class Node:
def __init__(self, data):
self.data = data
self.left = None
self.right = None
def printPaths(root):
path = []
printPathsRec(root, path, 0)
def printPathsRec(root, path, pathLen):
if root is None:
return
if(len(path) > pathLen):
path[pathLen] = root.data
else:
path.append(root.data)
pathLen = pathLen + 1
if root.left is None and root.right is None:
printArray(path, pathLen)
else:
printPathsRec(root.left, path, pathLen)
printPathsRec(root.right, path, pathLen)
def printArray(ints, len):
for i in ints[0 : len]:
print(i," ",end="")
print()
from binarytree import build
values = [7, 3, 2, 6, 9, None, 1, 5, 8]
root = build(values)
print(root)
printPaths(root.value)
.
I need to build binary tree with build and make the code work, but i can't find out the way.
This example is get from internet,they use method like
root = Node(10)
root.left = Node(8)
root.right = Node(2)
root.left.left = Node(3)
root.left.right = Node(5)
root.right.left = Node(2)
printPaths(root)
But i need to use another method to make it happen.
I am going to guess that values contains the level-order values of the tree, where the children below a None are not included (instead of having two filler None values).
Then the algorithm to populate a new tree will also follow a level-order way of populating. For this you typically use a queue or deque or two lists. For example:
def build(values):
if not values:
return
it = iter(values)
root = Node(next(it))
level = [root]
while level:
nextlevel = []
for parent in level:
value = next(it, None)
if value is not None:
parent.left = Node(value)
nextlevel.append(parent.left)
value = next(it, None)
if value is not None:
parent.right = Node(value)
nextlevel.append(parent.right)
level = nextlevel
return root
To create binary Tree:
you need a list sequential.
class Node:
count = 0
def __init__(self, val):
self.left = None
self.right = None
self.val = val
Node.count+= 1
def __str__(self):
return (f"value is {self.val} \ncount is:{self.count}")
If info is given as:
from collections import deque
d = {0:[1,2], 2:[4,5], 1:[3]} # how nodes are connected. key is node number and values is node num of children.
vals = [10,11,12,13,14,15] # values associated with the node num
q = deque()
q.append(0) #<---- root node
li = [vals[0]] #<--- root node val
while(len(q)>0):
front = q.popleft()
if (d.get(front, 0)):
if(len(d[front])==2):
li.append(vals[d[front][0]])
li.append(vals[d[front][1]])
q.append(d[front][0])
q.append(d[front][1])
else:
li.append(vals[d[front][0]])
li.append(None)
q.append(d[front][0])
# q.append(d[front][1])
else:
li.append(None)
li.append(None)
This will give you list
li:
[10, 11, 12, 13, None, 14, 15, None, None, None, None, None, None]
build:
def build(values):
if not values:
return None
it = iter(values)
root=Node(next(it))
q = deque()
q.append(root)
while(q):
front = q.popleft()
val1 = next(it, None)
if (val1):
n1 = Node(val1)
q.append(n1)
front.left = n1
val2 = next(it, None)
if (val2):
n2 = Node(val2)
q.append(n2)
front.right = n2
return root
node = build(li)
To print in inorder:
def print_node(root):
if not root:
return
print_node(root.left)
print(root.val, end=" ")
print_node(root.right)
print_node(node)
13 11 10 14 12 15
Straight Forward:
from collections import deque
d = {0:[1,2], 2:[4,5], 1:[3]}
vals = [10,11,12,13,14,15]
q = deque()
root = Node(vals[0], 0)
q.append(root)
while(q):
node = q.popleft()
if (d.get(node.node_num, {})):
if(len(d[node.node_num])==2):
no1 = d[node.node_num][0]
node.left = Node(vals[no1],no1)
no2 = d[node.node_num][1]
node.right = Node(vals[no2], no2)
q.append(node.left)
q.append(node.right)
else:
no1 = d[node.node_num][0]
node.left = Node(vals[no1],no1)
q.append(node.left)
print_node(root)
13 11 10 14 12 15
Added 1 attribute for node_num in class Node
I am writing some code for traversing a tree:
root = [1, None, 2, 3]
class Treenode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
class Solution:
def post_order_traversal_iterative(self,root):
stack = [root]
output = []
if not root:
return []
while stack:
curr = stack.pop()
output.append(curr.val)
if curr.right:
stack.append(curr.right)
if curr.left:
stack.append(curr.left)
return output
x = Solution()
print(Solution.post_order_traversal_iterative(x,root))
But I am getting the error that a 'list object has no attribute val'- which I totally get, but then how do I pass in my list as the input??
There are a few issues in your code:
post_order_traversal_iterative expects a Treenode instance but you're passing it a list instead; you should do something like root = Treenode() and then x.post_order_traversal_iterative(root)
once again since you put on the stack the left and right values of the current node they too should be instances of Treenode, not integer
apart from being a list and not a Treenode your root contains four elements while three are requested
So assuming you were trying to create a mini tree with just a root node "1" with two children "2" and "3" you should have something like
rootnode = Treenode(val=1)
firstchild = Treenode(val=2)
secondchild = Treenode(val=3)
rootnode.left = firstchild
rootnode.right = secondchild
or more succinctly
rootnode = Treenode(val=1, left=Treenode(val=2), right=Treenode(val=3))
I'm just getting started with binary trees and I have this task where I have to do a preorder iterative traversal search for a given binary tree '[1,null,2,3]'.
I tried to use a new binarytree module that I found, but it didn't worked and I saw a youtube video where some guy did it recursively but I just can't figure out.
#Input = [1,null, 2,3]
# 1
# \
# 2
# /
# 3
#Expected output = [1,2,3]
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def preorderTraversal(self, root: TreeNode) -> List[int]:
I'm just clueless, I wrote an algorithm but I can't turn it into actual functional code. Also I don't understand how the root: TreeNode works. Does it turn every element of the list into a TreeNode object? So far my best try had been this and it's obviously wrong in many ways.
def preorderTraversal(self, root: TreeNode) -> List[int]:
result = []
for i in root:
if i =! root[0] and root.left =! None:
root.left = i
if root.left =! null:
root.left.left = i
elif root.left == null:
root.right.left = i
elif root.left
result.append(i)
elif root.right == None:
root.right = i
else:
continue
A few points:
Function preorderTraversal should have no self parameter; it is not a method of a class.
I have modified the TreeNode class to make it more convenient to specify its children TreeNode objects.
Function preorderTraversal takes as an argument a TreeNode object. As I mentioned in a comment, your statement, #Input = [1,null, 2,3], is difficult to make sense of.
You need to keep a last in/first out (LIFO) stack of unvisited TreeNode objects to implement an iterative (rather than recursive solution). In the code below, variable nodes serves that purpose.
The code:
from typing import List
class TreeNode:
def __init__(self, val, left=None, right=None):
self.x = val
self.left = left
self.right = right
n3 = TreeNode(3)
n2 = TreeNode(2, left=n3)
n1 = TreeNode(1, right=n2)
def preorderTraversal(root: TreeNode) -> List[int]:
result = []
nodes = []
nodes.append(root) # initial node to visit
while len(nodes): # any nodes left top visit?
node = nodes.pop() # get topmost element, which is the next node to visit
result.append(node.x) # "output" its value before children are visited
if node.right is not None:
# show this node must be visited
nodes.append(node.right) # push first so it is popped after node.left
if node.left is not None:
# show this node must be visited
nodes.append(node.left)
return result
print(preorderTraversal(n1))
Prints:
[1, 2, 3]
Or a more complicated tree:
10
/ \
8 2
/ \ /
3 5 2
n3 = TreeNode(3)
n5 = TreeNode(5)
n8 = TreeNode(8, left=n3, right=n5)
n2a = TreeNode(2)
n2b = TreeNode(2, left=n2a)
n10 = TreeNode(10, left=n8, right=n2b)
print(preorderTraversal(n10))
Prints:
[10, 8, 3, 5, 2, 2]
You can use the queue data structure for it.
queue = []
result = []
queue.append(root)
while queue:
node = queue.pop()
result.append(node.val)
if node.left is not None:
queue.insert(0, node.left)
if node.right is not None:
queue.insert(0, node.right)
return result
This is a problem from leetcode platform, here is my solution. Runtime: 28 ms, faster than 81.08% of Python3 online submissions for Binary Tree Preorder Traversal.
class Solution:
def preorderTraversal(self, root: TreeNode) -> List[int]:
if not root:
return []
return [root.val] + self.preorderTraversal(root.left) + self.preorderTraversal(root.right)
I'm scratching my head for an hour.
I implemented binary tree in-order traversal using the iterator & stack.
class Node:
def __init__(self, val, left, right):
self.val = val
self.left = left
self.right = right
class BTIterator:
def __init__(self, root):
self.stack = [] # Use a list as a stack by using pop() & append()
self.root = root
self.leftmost = None
def Run(self):
node = self.root
while (node.left != None):
self.stack.append(node)
node = node.left
print(self.stack)
self.leftmost = node
print(self.leftmost.val)
while (self.Next(node) != None):
node = self.Next(node)
print(node.val)
def Next(self, node):
if (node.left != None):
while (node.left != None):
self.stack.append(node.left)
node = node.left
return node
elif (node.right != None):
node = node.right
while (node.left != None):
self.stack.append(node)
node = node.left
return node
else:
if self.stack != []:
node = self.stack.pop()
node.left = None
return node
if __name__ == '__main__':
# Let's construct the tree.
n12 = Node(12, None, None)
n11 = Node(11, None, n12)
n9 = Node(9, None, None)
n10 = Node(10, n9, n11)
n15 = Node(15, None, None)
n13 = Node(13, n10, n15)
n5 = Node(5, None, None)
n3 = Node(3, None, n5)
n7 = Node(7, n3, n13)
bti = BTIterator(n7)
bti.Run()
I also ran above implementation on IDE. From debugging, I clearly see def Next(self, node) returns n7. However once node = self.Next(node) line gets the n7, it turns n7 into None. Why?!
I think this must be a python syntax that I do not know.
Any pointer will be appreciated.
in your implementation, there are three problems I want to point out:
the main problem is your implemtation in Next is incorrect. Because inorder traversal is left->root->right, if (node.left != None): part is correct, but here:
elif (node.right != None):
node = node.right
while (node.left != None):
self.stack.append(node)
node = node.left
return node
you should return node itself first before deal with right child.
else:
if self.stack != []:
node = self.stack.pop()
node.left = None
return node
and you should not only pop when node is leaf, you should push every node in stack, and pop every Next.
you can not put Next in both while condition and block, because it will call twice.
while (self.Next(node) != None):
node = self.Next(node)
!= None in if (node.left != None): is not needed in python, you can just use if node.left:
because Next has many problems, so I have to rewrited Next, here is the version I edited based on your code, and I have commented in details:
class BTIterator:
def __init__(self, root):
self.stack = [] # Use a list as a stack by using pop() & append()
self.root = root
def Run(self):
# find the left most node, which means then first node
node = self.root
while node.left:
self.stack.append(node)
node = node.left
# start from left most node
while node:
print(node.val)
node = self.Next(node)
def Next(self, node):
# find right node, if it is none, it's ok, we will deal with it afterwards
node = node.right
# reach the end
if not self.stack and not node:
return None
# push left child iteratively
while node:
self.stack.append(node)
node = node.left
# this is next node we want
return self.stack.pop()
Hope that helps you, and comment if you have further questions. : )
I want to print a binary tree level by level iteratively without using a dequeue or any other data structure besides a python list. I have looked online and most do it one of those ways mentioned above.
If I have a tree:
41
/ \
7 53
/ \ /
1 19 47
I want it to print like:
41
7
53
1
19
47
This is my shot at it but it doesn't print out all the values in the bst:
def levelorder(self):
current = self._root
current_left = current_right = self._root
a = [current._value]
while current_left is not None and current_right is not None:
current_left = current_left._left
current_right = current_right._right
if current_left is not None:
a.append(current_left._value)
if current_right is not None:
a.append(current_right._value)
return a
This is what it outputs:
[41, 7, 53, 1]
Any ideas what is wrong with my code? and how I can approach the solution to this problem?
TREE CLASS:
class _BSTNode:
def __init__(self, value):
self._value = copy.deepcopy(value)
self._left = None
self._right = None
self._height = 1
return
class BST:
def __init__(self):
self._root = None
self._count = 0
self.comparisons = 0
return
def levelorder(self):
levels = [[self._root]]
while levels[-1]:
nextlevel = []
for node in levels[-1]:
nextlevel.extend([node for node in (node._left, node._right) if node])
levels.append(nextlevel)
return levels[:-1]
and my main part:
b = BST()
b.insert(41)
b.insert(7)
b.insert(53)
b.insert(1)
b.insert(19)
b.insert(47)
print (b.levelorder())
Without testing, as I don't have your Tree class, but I hope the general idea applies:
def levelorder(tree):
levels = [ [tree.root] ]
while levels [-1]:
nextLevel = []
for node in levels [-1]:
nextLevel.extend ( [node for node in (node.left, node.right) if node] )
levels.append (nextLevel)
return levels # or maybe levels [:-1]
Fully working example:
#! /usr/bin/python3
class Node:
def __init__(self, payload, left = None, right = None):
self.payload = payload
self.left = left
self.right = right
def __repr__(self):
return self.payload
class Tree:
def __init__(self, root):
self.root = root
def levels(self):
levels = [[self.root]]
while levels[-1]:
nextLevel = []
for node in levels[-1]:
nextLevel.extend([node for node in (node.left, node.right) if node])
levels.append(nextLevel)
return levels[:-1]
t = Tree(Node('41', Node('7', Node('1'), Node('19')), Node('53', Node('47'))))
print(t.levels())
Output is [[41], [7, 53], [1, 19, 47]]