i have this code that suppose seek the node in a binary tree:
def seekNode(self, node):
if self.id == node:
return self
elif self.left != None:
self.left.seekNode(node)
elif self.right != None:
self.left.seekNode(node)
else:
return False
but it returns a None object.
Here is the complete class:
class BinTree:
def __init__(self, id=None):
self.id= id
self.left= None
self.right= None
def setId(self, id):
if self.id == None:
self.id= id
return self
else:
return self.seekNode(id)
def addChildLeft(self, left):
if self.left == None:
self.left= BinTree(left)
else:
self.left.addChildLeft(left)
def addChildRight(self, right):
if self.right == None:
self.right= BinTree(right)
else:
self.right.addChildRight(right)
def seekNode(self, node):
if self.id == node:
return self
elif self.left != None:
self.left.seekNode(node)
elif self.right != None:
self.left.seekNode(node)
else:
return False
i only call setuId function, i debugged the code (i'm not expert doing this) and i saw that the function returned de object, but when i save this search, it turns in None object.
You are missing return before the recursive calls to self.left.seek(...) and self.right.seek(...). The user of the tree also should not have to concern him/herself with addLeft or addRight - a simple insert method should automatically insert a new node in the proper location.
I would also point out recursion is a functional heritage and using it with functional style will yield the best results. This means avoiding things variable reassignment, other mutations, and side effects.
Let's see what it would look like to implement btree in this way -
# btree.py
def empty():
return None
def insert(t, v):
if not t:
return node(v) # empty
elif v < t.data:
return node(t.data, insert(t.left, v), t.right) # insert left
elif v > t.data:
return node(t.data, t.left, insert(t.right, v)) # insert right
else:
return t # no change
def seek(t, v):
if not t:
return None # no match
elif v < t.data:
return seek(t.left, v) # seek left
elif v > t.data:
return seek(t.right, v) # seek right
else:
return t # match
The data structure for node can be anything you want. Here's a dead-simple interface. Notice how the left and right properties can be set when a new node is constructed -
class node:
def __init__(self, data, left=None, right=None):
self.data = data
self.left = left
self.right = right
Related
I have implemented a binary search tree and it is working fine except for the case where I have to delete a node with two children. The following is my code for the delete method:
def find(self, node):
curr = node
while curr.left is not None:
curr = curr.left
return curr
def delete(self, key):
node_to_remove = self._search(key, self.root)
if node_to_remove.left is None and node_to_remove.right is None:
#Then we identify this as a leaf node
if node_to_remove is node_to_remove.parent.left:
#Setting the parent's reference to this to None
node_to_remove.parent.left = None
elif node_to_remove is node_to_remove.parent.right:
node_to_remove.parent.right = None
#2nd Case --> Two child
elif node_to_remove.left and node_to_remove.right:
minimum = self.find(node_to_remove.right)
node_to_remove = minimum
self.delete(minimum.key)
#3rd Case -> One child
else:
if node_to_remove.left:
node_to_remove.left.parent = node_to_remove.parent
node_to_remove.parent.left = node_to_remove.left
elif node_to_remove.right:
node_to_remove.right.parent = node_to_remove.parent
node_to_remove.parent.right = node_to_remove.right
Any indicators on how to fix the second case would be of immense help!
You'll need to take the value of the deeper deleted node and assign it to the node that has the two children. So that block should look like this:
elif node_to_remove.left and node_to_remove.right:
minimum = self.find(node_to_remove.right)
self.delete(minimum.key)
node_to_remove.key = minimum.key
Other remarks
Your code will run into an exception when the root has the value to delete and it has no two children. In that case your code wants to access the parent node, which the root node does not have. Furthermore, such a deletion should result in a different value for this.root.
Here is the suggested correction:
def delete(self, key):
node_to_remove = self._search(key, self.root)
if node_to_remove.left is None and node_to_remove.right is None:
if node_to_remove is self.root:
self.root = None
elif node_to_remove is node_to_remove.parent.left:
node_to_remove.parent.left = None
elif node_to_remove is node_to_remove.parent.right:
node_to_remove.parent.right = None
#2nd Case --> Two child
elif node_to_remove.left and node_to_remove.right:
minimum = self.find(node_to_remove.right)
self.delete(minimum.key)
node_to_remove.key = minimum.key
#3rd Case -> One child
else:
if node_to_remove.left:
node_to_remove.left.parent = node_to_remove.parent
if node_to_remove is self.root:
self.root = node_to_remove.left
else:
node_to_remove.parent.left = node_to_remove.left
elif node_to_remove.right:
node_to_remove.right.parent = node_to_remove.parent
if node_to_remove is self.root:
self.root = node_to_remove.right
else:
node_to_remove.parent.right = node_to_remove.right
A second remark: your tree is threaded (i.e. it has parent references). It is possible to do this for a non-threaded tree, and also with less code.
Seeking advise on how structure python to create a maze, solve it with BFS and to have basic navigation within maze with number of moves required to navigate. Use move along the path, Up, Left, Right, Down. Below is some code that I mangled together to think about and figure how to structure python for this BFS algorithm code.
Is anyone open to mentoring on this BFS algorithm navigation maze python structure?
To basically follow the following algorithm:
function BREADTH-FIRST-SEARCH(problem) returns a solution node or failure
node ← NODE(problem.INITIAL)
if problem.IS-GOAL(node.STATE) then return node
frontier ← a FIFO queue, with node as an element
reached ← {problem.INITIAL}
while not IS-EMPTY(frontier ) do
node ← POP(frontier )
for each child in EXPAND(problem, node) do
s ← child.STATE
if problem.IS-GOAL(s) then return child
if s is not in reached then
add s to reached
add child to frontier
return failure
import sys
def parse_map(filename):
with open(filename, "r") as f:
return [[char for char in line] for line in f.read().rstrip("\n").split("\n")][3:]
def count_x(house_map):
return sum([ row.count('p') for row in house_map ] )
def printable_house_map(house_map):
return "\n".join(["".join(row) for row in house_map])
def add_x(house_map, row, col):
return house_map[0:row] + [house_map[row][0:col] + ['p',] + house_map[row][col+1:]] + house_map[row+1:]
def successors(house_map):
return [ add_x(house_map, r, c) for r in range(0, len(house_map)) for c in range(0,len(house_map[0])) if house_map[r][c] == '.' ]
def is_goal(house_map, k):
return count_x(house_map) == k
def bfs_graph_search(house_map):
fringe = [initial_house_map]
if house_map.goal_test(node.state):
return fringe
fringe = deque([house_map])
visited = set()
while fringe:
fringe = fringe.popleft()
visited.add(node.state)
for child in node.expand(problem):
if child.state not in fringe and child not in visited:
if house_map.goal_test(child.state):
return child
fringe.append(child)
return None
def solve(initial_house_map,k):
fringe = [initial_house_map]
while len(fringe) > 0:
for new_house_map in successors( fringe.pop() ):
if is_goal(new_house_map,k):
return(new_house_map,True)
fringe.append(new_house_map)
if __name__ == "__main__":
house_map=parse_map('map1.txt')
k = 2
print ("Initial ]house map:\n" + printable_house_map(house_map) + "\n\nSearching for solution...\n")
solution = solve(house_map,k)
print ("Found:")
print (printable_house_map(solution[0]) if solution[1] else "False")
class Agent:
def __init__(self, initial, goal=None):
self.initial = initial
self.goal = goal
def actions(self, state):
raise NotImplementedError
def result(self, state, action):
raise NotImplementedError
def goal_test(self, state):
if isinstance(self.goal, list):
return is_in(state, self.goal)
else:
return state == self.goal
def path_cost(self, c, state1, action, state2):
return c + 1
def value(self, state):
raise NotImplementedError
class FringeGraph:
def __init__(self, state, parent=None, action=None, path_cost=0):
self.state = state
self.parent = parent
self.action = action
self.path_cost = path_cost
self.depth = 0
if parent:
self.depth = parent.depth + 1
def path(self):
node, path_back = self, []
while node:
path_back.append(node)
node = node.parent
return list(reversed(path_back))
def solution(self):
return [node.action for node in self.path()[1:]]
def expand(self, agent):
return [self.child_node(agent, action)
for action in agent.actions(self.state)]
def child_node(self, agent, action):
next_state = agent.result(self.state, action)
next_node = Node(next_state, self, action, problem.path_cost(self.path_cost, self.state, action, next_state))
return next_node
class Agent:
def __init__(self, initial, goal=None):
self.initial = initial
self.goal = goal
def actions(self, state):
raise NotImplementedError
def result(self, state, action):
raise NotImplementedError
def goal_test(self, state):
if isinstance(self.goal, list):
return is_in(state, self.goal)
else:
return state == self.goal
def path_cost(self, c, state1, action, state2):
return c + 1
def value(self, state):
raise NotImplementedError
class FringeGraph:
def __init__(self, state, parent=None, action=None, path_cost=0):
self.state = state
self.parent = parent
self.action = action
self.path_cost = path_cost
self.depth = 0
if parent:
self.depth = parent.depth + 1
def path(self):
node, path_back = self, []
while node:
path_back.append(node)
node = node.parent
return list(reversed(path_back))
def solution(self):
return [node.action for node in self.path()[1:]]
def expand(self, agent):
return [self.child_node(agent, action)
for action in agent.actions(self.state)]
def child_node(self, agent, action):
next_state = agent.result(self.state, action)
next_node = Node(next_state, self, action, agent.path_cost(self.path_cost, self.state, action, next_state))
return next_node
I am trying to find a solution in Python to try and move the pre-order notation e.g."* + 7 3 - 2 9" or "+ 55 26" to post notation or the reverse polish notation. the expected result would be e.g. "7 3 + 2 9 - *" and "55 26 +" respectively. I did some research on the binary trees however with the math functions I am struggling. What I have currently is the following:
class Node:
def __init__(self, data):
self.left = None
self.right = None
self.data = data
Function to check for operators
def isOperator(self, c):
return c == '+' or c == '-' or c == '*' or c == '/'
Insert Node
def insert(self, data):
if self.data:
if data < self.data:
if self.left is None:
self.left = Node(data)
else:
self.left.insert(data)
elif data > self.data:
if self.right is None:
self.right = Node(data)
else:
self.right.insert(data)
else:
self.data = data
Print the Tree
def PrintTree(self):
if self.left:
self.left.PrintTree()
print( self.data),
if self.right:
self.right.PrintTree()
Preorder traversal
Root -> Left ->Right
def PreorderTraversal(self, root):
res = []
if root:
res.append(root.data)
res = res + self.PreorderTraversal(root.left)
res = res + self.PreorderTraversal(root.right)
return res
Postorder traversal
Left ->Right -> Root
def PostorderTraversal(self, root):
res = []
if root:
res = self.PostorderTraversal(root.left)
res = res + self.PostorderTraversal(root.right)
res.append(root.data)
return res
Any assistance in getting this code complete will be highly appreciated, as I am not able to figure this out.
Thank you in advance
First some issues:
Your insert method applies binary search tree logic, which is not relevant for the expression tree you want to build. Instead it should keep track of the insertion spot for any next data.
It is not clear whether these are all methods of the Node class, but at least isOperator is unrelated to any instance values, so it should not be a method (with self argument), but either a stand alone function or a static method. Moreover, if the input is valid, then an operator is anything that is not a number.
Methods should not print (except for debugging purposes): leave that for the main driver code to do. Methods can help printing by returning an iterator, or a representation (implementing __repr__).
It is common practice to not use an initial capital letter for function names and reserve that for class names.
I would suggest a separate class for the tree. This will be handy to track where the next node should be inserted, using a path (stack).
Here is how you could implement it:
class Node:
def __init__(self, data, left=None, right=None):
self.left = left
self.right = right
self.data = data
def __iter__(self): # default iteration is inorder
if self.left:
yield from self.left
yield self.data
if self.right:
yield from self.right
def preorder(self):
yield self.data
if self.left:
yield from self.left.preorder()
if self.right:
yield from self.right.preorder()
def postorder(self):
if self.left:
yield from self.left.postorder()
if self.right:
yield from self.right.postorder()
yield self.data
class Tree:
def __init__(self):
self.root = None
self.path = []
def insert(self, data):
if not self.root:
node = self.root = Node(data)
elif not self.path:
raise ValueError("Cannot add more nodes")
elif self.path[-1].left:
node = self.path[-1].right = Node(data)
else:
node = self.path[-1].left = Node(data)
if not data.isnumeric(): # internal node
self.path.append(node)
else:
while self.path and self.path[-1].right:
self.path.pop()
#staticmethod
def fromstr(s):
tree = Tree()
for token in s.split():
tree.insert(token)
return tree
def __iter__(self):
if self.root:
yield from self.root
def preorder(self):
if self.root:
yield from self.root.preorder()
def postorder(self):
if self.root:
yield from self.root.postorder()
Here is how you can run it:
def postorder(s):
tree = Tree.fromstr(s)
# Just for debugging, print the tree in inorder:
print(*tree) # this calls `__iter__`
return " ".join(tree.postorder())
print(postorder("* + 7 3 - 2 9"))
Output (inorder and postorder):
7 + 3 * 2 - 9
7 3 + 2 9 - *
I have tried various methods in order to calculate the height of a Binary Search Tree which includes recursion and also using a list in order to add the node along with it's depth.But for both the methods,the output is not correct.
Here's my code for the same:
class Node:
def __init__(self,data):
self.data=data
self.left=None
self.right=None
def Insert_BTreeNode(self,data):
if self.data:
if data<=self.data:
if self.left is None:
self.left=Node(data)
else:
self.left.Insert_BTreeNode(data)
elif data>self.data:
if self.right is None:
self.right=Node(data)
else:
self.right.Insert_BTreeNode(data)
else:
self.data=data
def Lookup(self,data,parent=None):
if data<self.data:
if self.left is None:
return None,None
return self.left.Lookup(data,self)
elif data>self.data:
if self.right is None:
return None,None
return self.right.Lookup(data,self)
else:
if (parent is not None):
print(self.data,parent.data)
return (self,parent)
def Children_count(self):
count=0
if self.left:
count+=1
if self.right:
count+=1
return (count)
def Delete(self,data):
children_count=0
node,parent=self.Lookup(data)
if node is not None:
children_count=node.Children_count()
if children_count==0:
if parent:
if parent.left is Node:
parent.left=None
else:
parent.right=None
del node
else:
self.data=data
elif children_count==1:
if node.left:
n=node.left
else:
n=node.right
if parent:
if parent.left is node:
parent.left=n
else:
parent.right=n
del node
else:
self.left=n.left
self.right=n.right
self.data=n.data
else:
parent=node
successor=node.right
while successor.left:
parent=successor
successor=successor.left
node.data=successor.data
if parent.left==successor:
parent.left=successor.right
else:
parent.right=successor.right
def print_treeInorder(self):
if self.left:
self.left.print_treeInorder()
print(self.data)
if self.right:
self.right.print_treeInorder()
def print_treePostorder(self):
if self.left:
self.left.print_treePostorder()
if self.right:
self.right.print_treePostorder()
print(self.data)
def height(self):
if self is None:
return 0
else:
return max(height(self.getLeft()), height(self.getRight()))+ 1
def print_treePreorder(self):
print(self.data)
if self.left:
self.left.print_treePreorder()
if self.right:
self.right.print_treePreorder()
def getLeft(self):
return self.left
def getRight(self):
return self.right
def maxDepth(self): #Level order Traversal
if self is None:
return 1
q=[]
q.append([self,1])
while(len(q))!=0:
node,temp=q.pop()
if node.getLeft()!=None:
q.append([node.getLeft(),temp+1])
if node.getRight()!=None:
q.append([node.getRight(),temp+1])
return temp
b_tree_input=list(map(int,input().split()))
root=Node(b_tree_input[0])
for i in range(1,len(b_tree_input)):
root.Insert_BTreeNode(b_tree_input[i])
print(root.height())
print(root.maxDepth())
For the sample input of 2,1,3,4.Both the function should return the answer as 3 but the height function returns the following.
NameError: name 'height' is not defined
While the maxDepth() function returns the answer as 2.
Regarding height: I'm not a python programmer, but shouldn't it be
max(self.getLeft().height(), self.getRight().height())
// instead of
max(height(self.getLeft()), height(self.getRight()))
since height is a member function?
However, this implies you have to check self.getLeft() and self.getRight() for None values before calling height. If you don't want to do the extra checks, think of making height a global function unrelated to your class, then your previous approach on recursion should work.
The height function with checks for None could look as follows (no guarantee on the syntax details):
def height(self):
if self is None:
return 0
elif self.left and self.right:
return max(self.left.height(), self.right.height()) + 1
elif self.left:
return self.left.height() + 1
elif self.right:
return self.right.height() + 1
else:
return 1
In maxDepth you process child nodes in a right-to-left DFS but you only take the result of the last processed path instead of comparing current temp to the maximum of already found depths.
So in your [2,1,3,4] example, the execution order is as follows:
q=[[2,1]] -> take [2,1] -> temp=1
q=[[1,2],[3,2]] -> take [3,2] -> temp=2
q=[[1,2],[4,3]] -> take [4,3] -> temp=3
q=[[1,2]] -> take [1,2] -> temp=2
end
I think you can now figure out how to change your algorithm.
Also you should consider to change the self is None case to return 0.
I'm working on a binary tree in Python3 and so far almost everything has been working like expected; however, I have a function that is supposed to return a list of all children for any given node and for whatever reason I'm only getting a list of the object addresses, and not calling my overridden __str__(self) method.
from collections import deque # http://docs.python.org/3.1/tutorial/datastructures.html
class BinaryNode: # binary tree functionality via iterative means
def __init__(self, name, data):
self.Left = None
self.Right = None
self.Parent = None
self.Name = name
self.Data = data
return
def AddNew(self, name, data):
q = []
q.append(self)
while q:
i = q.pop()
if i.Name == name:
i.Data = data
return i
elif name < i.Name:
if i.Left:
q.append(i.Left)
else:
i.Left = BinaryNode(name, data)
i.Left.Parent = i
return i.Left
else:
if i.Right:
q.append(i.Right)
else:
i.Right = BinaryNode(name, data)
i.Right.Parent = i
return i.Right
def Find(self, name):
q = deque()
q.append(self)
'''if self.Left: q.append(self.Left)
if self.Right: q.append(self.Right)'''
while q:
i = q.pop()
print(i)
if i.Name == name:
return i
elif name < i.Name:
if i.Left: q.append(i.Left)
else: return None
else:
if i.Right: q.append(i.Left)
else: return None
def Children(self):
children = []
q = deque()
if self.Left: q.append(self.Left)
if self.Right: q.append(self.Right)
while q:
i = q.popleft()
if i.Left: q.append(i.Left)
if i.Right: q.append(i.Right)
children.append(i)
return children
def Parents(self):
lst = []
i = self.Parent
while i is not None:
lst.append(i)
i = i.Parent
return lst
def __str__(self): return "{} : {}".format(self.Name, self.Data)
and I'm testing it by calling
test = BinaryNode("Jesse", 21)
print(test)
print(test.AddNew("David", 22))
print(test.AddNew("Marli", 23))
print(str(test.Children()))
print(test.Find("David"))
print(test.Find("David").Children())
print(test.Find("Gary")) #Will return None
with the resulting console output
Jesse : 21
David : 22
Marli : 23
[<__main__.BinaryNode object at 0x000000000333E160>, <__main__.BinaryNode object at 0x000000000333E1D0>, <__main__.BinaryNode object at 0x000000000333E198>]
David : 22
[<__main__.BinaryNode object at 0x000000000333E1D0>]
None
UPDATE:
Here is the answer I implemented:
def __repr__ (self): return str(self)
Python containers always use the representation of contained objects.
Implement a __repr__ method too and that'll be used when printing the list; you can make it an alias for __str__ if you wish:
__repr__ = __str__
or explicitly print each element in your list:
print(', '.join(map(str, test.Children())))