Binary Tree Preorder Traversal - python

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)

Related

Inserting a node in a complete binary tree with python

How to insert a node in a complete binary tree without using queue DS? I tried the following code:
class TreeNode:
def __init__(self, value=None) -> None:
self.left = None
self.value = value
self.right = None
class Tree:
def __init__(self, root=None) -> None:
self.__root = root if not root else TreeNode(root)
self.__len = 1 if root else 0
def append(self, data, root="_"):
if self.__root.value is None:
self.__root = TreeNode(data)
self.__len += 1
return
root = self.__root if root == "_" else root
if not root:
return False
if root.left is None and root.right is None:
root.left = TreeNode(data)
self.__len += 1
return True
elif root.left is not None and root.right is None:
root.right = TreeNode(data)
self.__len += 1
return True
elif root.left is not None and root.right is not None:
if self.append(data, root.left):
return
else:
self.append(data, root.right)
return
the recursive call of that function always add the new node on the left side of the tree, so what should I do to make it recursively checks the right side too?
First of all, the first line in your append code seems to give a special meaning to the value in the root node. When it is None it is not considered a real node, but to represent an empty tree. This is not a good approach. An empty tree is represented by a __root that is None -- nothing else. I would also suggest to remove the optional data argument from the constructor. Either the constructor should allow an arbitrary number of values or none at all. To allow one is odd and strengthens the idea that a tree could have a special None in its root node.
To the core of your question. There is nice attribute to complete binary trees. The paths from the root to a leaf can be represented by a bit pattern, where a 0 means "go left" and a 1 means "go right". And the path to the "slot" where a new node should be injected has a relationship with the size of the tree once that node has been added:
new size
binary representation
path to new node
1
1
[]
2
10
[left]
3
11
[right]
4
100
[left,left]
5
101
[left,right]
In general the path to the new node is defined by the bits in the binary representation of the new tree size, ignoring the leftmost 1.
This leads to the following code:
class Tree:
def __init__(self) -> None:
self.__root = None
self.__len = 0
def append(self, data):
self.__len += 1
if self.__len == 1: # First node
self.__root = TreeNode(data)
return
node = self.__root
# Iterate all the bits except the leftmost 1 and the final bit
for bit in bin(self.__len)[3:-1]:
node = [node.left, node.right][int(bit)] # Choose side
if self.__len & 1: # Use final bit to determine where child goes:
node.right = TreeNode(data)
else:
node.left = TreeNode(data)

Recursive solution to flatten binary tree to linked list

Here is the link for problem description:
Flatten Binary Tree to Linked List has:
# class TreeNode(object):
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution(object):
def flatten(self, root):
"""
:type root: TreeNode
:rtype: None Do not return anything, modify root in-place instead.
"""
The solution is:
class Solution:
def flattenTree(self, node):
# Handle the null scenario
if not node:
return None
# For a leaf node, we simply return the
# node as is.
if not node.left and not node.right:
return node
# Recursively flatten the left subtree
leftTail = self.flattenTree(node.left)
# Recursively flatten the right subtree
rightTail = self.flattenTree(node.right)
# If there was a left subtree, we shuffle the connections
# around so that there is nothing on the left side
# anymore.
if leftTail:
leftTail.right = node.right
node.right = node.left
node.left = None
# We need to return the "rightmost" node after we are
# done wiring the new connections.
return rightTail if rightTail else leftTail
def flatten(self, root: TreeNode) -> None:
"""
Do not return anything, modify root in-place instead.
"""
self.flattenTree(root)
I don't understand this block of code:
if leftTail:
leftTail.right = node.right (step 1)
node.right = node.left (step 2)
node.left = None
For example, if the binary tree input is [1, 2, 3], the leftTail after step 1 will be: [2, null, 3]. My naive thought is after step 2, the tree becomes [1, null, 3] but to my surprise, it becomes: [1,null,2,null,3].
Suppose your example with tree [1, 2, 3]:
1 (node)
/ \
2 3
And lets check what was done by every step:
if leftTail:
leftTail.right = node.right (step 1)
node.right = node.left (step 2)
node.left = None (step 3)
Step 1:
1 (node)
/ \
2 3
\
3 (same as above)
Step 2:
1 (node)
/ \
2 2 (same as left)
\ \
3 3
Step 3:
1 (node)
\
2
\
3
So, [1, null, 2, null, 3] is achieved.

Binary Tree Iterative Inorder Traversal

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

python binary tree iterator - why returned node becomes None?

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. : )

Inorder successor in a binary search tree

This is a common algorithm question. I'm trying to find the inorder successor in a binary search tree. Here's my code
def inorderSuccessor(self, root, p):
"""
:type root: TreeNode
:type p: TreeNode
:rtype: TreeNode
"""
# if Node has a right child, go all the way down
if p.right:
curr = p
while curr.left:
curr = curr.left
return curr
# first ancestor whose left child the node is
ans = None
curr = root
while curr is not p:
if curr.val < p.val:
curr = curr.right
else:
ans = curr
curr = curr.left
return ans
The problem is that this doesn't work when p is the highest node in the tree. I've been scratching my head over how to get this edge case going.
You can implement a method within your BST Class as below
def InOrderSucc(self,childNode):
if(self.search(childNode)):
if not (self.data == childNode):
return(self.right.InOrderSucc(childNode))
else:
if(self.right):
return(self.right.data)
else:
return None
else:
return False
where childNode is the Node you are requesting to find its InOrder Successor, Noting that the InOrder Successor will always be the right Child.

Categories

Resources