Trying to add a preorder traversal method to my class - python

class node:
def __init__(self,value=None):
self.value=value
self.left_child=None
self.right_child=None
self.parent=None
class binary_search_tree:
def __init__(self):
self.root=None
def insert(self,value):
if self.root==None:
self.root=node(value)
else:
self._insert(value,self.root)
def _insert(self,value,cur_node):
if value<cur_node.value:
if cur_node.left_child==None:
cur_node.left_child=node(value)
cur_node.left_child.parent=cur_node
else:
self._insert(value,cur_node.left_child)
elif value>cur_node.value:
if cur_node.right_child==None:
cur_node.right_child=node(value)
cur_node.right_child.parent=cur_node
else:
self._insert(value,cur_node.right_child)
else:
print("Value already in tree!")
def print_tree(self):
if self.root!=None:
self._print_tree(self.root)
def _print_tree(self,cur_node):
if cur_node!=None:
self._print_tree(cur_node.left_child)
print (str(cur_node.value))
self._print_tree(cur_node.right_child)
def height(self):
if self.root!=None:
return self._height(self.root,0)
else:
return 0
def _height(self,cur_node,cur_height):
if cur_node==None: return cur_height
left_height=self._height(cur_node.left_child,cur_height+1)
right_height=self._height(cur_node.right_child,cur_height+1)
return max(left_height,right_height)
def find(self,value):
if self.root!=None:
return self._find(value,self.root)
else:
return None
def _find(self,value,cur_node):
if value==cur_node.value:
return cur_node
elif value<cur_node.value and cur_node.left_child!=None:
return self._find(value,cur_node.left_child)
elif value>cur_node.value and cur_node.right_child!=None:
return self._find(value,cur_node.right_child)
def preorder(self):
print(self.value)
if self.left_child:
self.left_child.preorder()
if self.right_child:
self.right_child.preorder()
tree = binary_search_tree()
tree.insert(21)
tree.insert(26)
tree.insert(30)
tree.insert(9)
print(tree.preorder)
So I have this binary search tree class and it all works correctly, however I added a preorder traversal method inside of my class, and that is not working. Does anyone know how i could modify this method for it to work? I am looking for it to just print out the preorder list. Should I add the root or value as a parameter to the method? I am just looking to be able to get it to preorder traversal and just print it, thats all i really need.

Preorder would be just a matter of changing the order of statements in _print_tree(). Something like this:
def preorder(self):
if self.root!=None:
self._preorder(self.root)
def _preorder(self,cur_node):
if cur_node!=None:
print (str(cur_node.value))
self._preorder(cur_node.left_child)
self._preorder(cur_node.right_child)
And call it like tree.preorder()
I strongly recommend going through the theory or ordered tree traversal: https://www.geeksforgeeks.org/tree-traversals-inorder-preorder-and-postorder/

The problem is that you are mixing and matching two approaches to organizing the recursion.
Approach 1:
def _insert(self,value,cur_node):
# skipping logic, until we get to a recursive call:
self._insert(value,cur_node.left_child)
The general logic in here is that the recursive calls call back to the same tree object, but pass the information about which node is being operated on as a parameter. This keeps the logic out of the Node class, which is just plain data storage.
Approach 2:
def preorder(self):
# the recursive calls look instead like this:
self.left_child.preorder()
This attempts to implement the recursion by delegating to the node instances, which requires them to have the behaviour. This whole block of code makes sense as a node method, since it is the nodes that have left_child and right_child attributes (that can be accessed from self). If you want to take this approach, then that code goes in the node class, and then in the binary_search_tree you would just need to delegate to the root node:
def preorder(self):
self.root.preorder()
Either way, it is better if you pick one approach and stick with it: either
have the tree class delegate to the root node, and give the nodes the needed functionality to do the recursion; or
have the tree class handle the entire recursion, by keeping track of the "current" node. (You can also easily convert this approach to iteration.)

def preorder(self):
currentNode = self
if currentNode is not None:
print(currentNode.value)
if currentNode.left:
currentNode.left.preorder()
if currentNode.right:
currentNode.right.preorder()
try this

Related

Trying to save node or reference to node in a list

I have a tree class in which the class gets initialized with a data, left, and right attributes.
in the same class I have a "save" method.
I am using a list as a queue.
I am attempting to create a "save" method which takes only one argument "data".
The purpose of this save method is to dequeue from my list, check that node to see if its empty and if it is then it saves my data there. Otherwise it enqueues the 2 children of that node into the list.
The purpose of this is to save data in level order into the tree.
Because the class gets initialized there is always at least 1 element in the tree which is the root node.
The issue i keep running into is that whenever i append the self.data (the root node, not the data im currently trying to add) into my list at the beginning of the save method it only saves the data there.
and obviously when I then try to append the left and right child of this int i get an error because the int has no left or right attributes.
I am wondering how to save the node in the list instead of the data at the node.
class Tree():
aqueue = []
def __init__(self, item):
self.item = item
self.leftchild = None
self.rightchild = None
self.aqueue.append(self.item)
def add(self, newitem):
temp = self.myqueue.pop(0)
if temp is None:
temp = Tree(newitem)
else:
self.aqueue.append(temp.leftchild)
self.aqueue.append(temp.rightcild)
temp.add(newitem)
self.aqueue.clear() #this is meant to clear queue of all nodes after the recursions are complete
self.aqueue.append(self.item) #this is meant to return the root node to the queue so that it is the only item for next time
There are a couple of obvious issues with your code: both the if and else branch return, so the code after will never run, temp == newitem is an equality expression, but even if it was an assignment it wouldn't do anything:
def add(self, newitem):
temp = self.myqueue.pop(0)
if temp == None: # should use temp is None
temp == newitem # temp = newitem still wouldn't do anything
return True
else:
self.aqueue.append(temp.leftchild)
self.aqueue.append(temp.rightcild)
return temp.add(newitem)
# you will never get here, since both branches of the if returns
self.aqueue.clear() # delete everything in the list..?
self.aqueue.append(self.item)

Why we make Node class and LinkedList class instead of doing it simple way like

i have just started learning data structures and algorithms and i want to know why do we make node and linkedlist classes separately rather doing everything in a single class like i did
class LinkedList():
def __init__(self):
self.linked=[]
def add(self,data):
self.linked.append(data)
return self.linked
def get_size(self):
return len(self.linked)
def remove(self,data):
if data in self.linked:
while data in self.linked:
z=self.linked.index(data)
del self.linked[z]
print self.linked
return True
else:
return False
def find(self,data):
if data in self.linked:
return "Found" + " " + str(data)
else:
return "Not found" + " " + str(data)
Is that because of space and time complexity or some other factors?
Thanks again.
A linked list means that each element has a pointer (= link) to the next element in the list. A typical Node class stores that pointer. Your LinkedList class is just a wrapper for a standard Python list, not a linked list.

Local const in recursion call

Well... Code first.
def magic(node):
spells_dict = {"AR_OP":ar_op_magic, "PRE_OP":pre_op_magic}
if node:
if node.text in spells_dict:
return spells_dict[node.text](node)
else:
return magic(node.l) + magic(node.r)
else:
return ""
During recursion calls there will be created a lot of spells_dict copies. I know that I can make that dict global, but I don't want, because this dict related to magic function only. So, I can create some class and put spells_dict and function to it, but it don't looks like a good solution.
Is there any way how I can do it with only one copy of spells_dict?
I don't see any problems with a MAGIC_SPELLS constant. You can locale it near the magic function, so you know, the belong together:
def magic_default(node):
return magic(node.l) + magic(node.r)
MAGIC_SPELLS = {
'AR_OP': ar_op_magic,
'PRE_OP': pre_op_magic,
}
def magic(node):
if node:
func = MAGIC_SPELLS.get(node.text, magic_default)
return func(node)
return ""

How to build a binary search tree with python without pointers?

I have seen some answers to the question "how to build a binary tree", but the relate answers seem not to work!! They are based on algorithms more or less like this:
def insert(item, tree):
if (item < tree.entry):
if (tree.left != None):
insert(item, tree.left)
else:
tree.left = Tree(item)
else:
if (tree.right != None):
insert(item, tree.right)
else:
tree.right = Tree(item)
The code mentioned before has been written by Isaac1000, but other ones are very similar. The problem is that when tree.right or tree.left is passed to the function "insert" in the following calls:
insert(item, tree.left)
insert(item, tree.right)
the ones who wrote the code think to pass the reference, instead of a copy of the value, so that, tree.left or tree.right will not be really changed.
Finally, that function or similar just work at the first or zero level of the Tree, but not at the n level of the tree.
So, how to build a binary search tree without pointers?
P.S.
I said "without pointers" just because I know that python hasn't got pointers, but please tell me if I'm wrong
#qfiard
"If you pass a mutable object into a method, the method gets a reference to that same object and you can mutate it to your heart's delight, but if you rebind the reference in the method, the outer scope will know nothing about it, and after you're done, the outer reference will still point at the original object."(Blay Conrad)
That speech made me all clear. I have understood that my code didn't word because I was used to rebind tree.left. The following code was the code I have been using till now:
def insert(self, data):
if self is None:
self = Tree(data)
else:
if data < self.data:
Link.insert(self.left, data)
else:
Link.insert(self.right, data)
Finally, when I wrote self = Tree(data) I was trying to rebind an object and the outer scope didn't know nothing about it. Instead, using the procedure I have posted, when I use self.right or self.left I try to modify the object without rebinding, so that the outer scope remembers my changes.
Arguments in Python are passed by assignment, which is similar to passing arguments by reference for mutable types (lists, objects, ...). See this stackoverflow answer for more details on the subject: https://stackoverflow.com/a/986145/2887956 .
The code that you provided works therefore perfectly if you use objects to represent your trees. The following code outputs
<<None, 0, None>, 1, <None, 2, None>>
class Tree(object):
def __init__(self, entry):
self.entry = entry
self.left = None
self.right = None
def __str__(self):
return '<%s, %d, %s>' % (self.left, self.entry, self.right)
def insert(item, tree):
if item < tree.entry:
if tree.left is not None:
insert(item, tree.left)
else:
tree.left = Tree(item)
else:
if tree.right is not None:
insert(item, tree.right)
else:
tree.right = Tree(item)
root = Tree(1)
insert(0, root)
insert(2, root)
print root
Your algorithm would also work if you used lists to represent your trees, although you would need to modify it substantially.

Tree Path from Root to Selected Node - The Pythonic Way

In a python application we have a tree made up of TreeNode objects, and we had to add a property on the TreeNode class that returns the path from the tree root to that node as a list. We have implemented this in a simple recursive way, however the code looks a little verbose for python (we suspect there is a terser way of expressing a simple algorithm like this in python). Does anyone know a more pythonic way of expressing this?
Here is a simplified version of our code - it is the definition of path_from_root we are looking to improve:
class TreeNode(object):
def __init__(self, value, parent=None):
self.value = value
self.parent = parent
#property
def path_from_root(self):
path = []
_build_path_from_root(self, path)
return path
def _build_path_from_root(node, path):
if node.parent:
_build_path_from_root(node.parent, path)
path.append(node)
Below are some unit tests that show how path_from_root works:
class TreePathAsListTests(unittest.TestCase):
def setUp(self):
self.root = TreeNode(value="root")
self.child_1 = TreeNode(value="child 1", parent=self.root)
self.child_2 = TreeNode(value="child 2", parent=self.root)
self.leaf_1a = TreeNode(value="leaf 1a", parent=self.child_1)
def test_path_from_root(self):
self.assertEquals([self.root, self.child_1, self.leaf_1a], self.leaf_1a.path_from_root)
self.assertEquals([self.root, self.child_2], self.child_2.path_from_root)
self.assertEquals([self.root], self.root.path_from_root)
Update: Accepted an answer that was a clear improvement, but definitely still interested in any other ways of expressing this.
I would do it this way:
#property
def path_from_root(self):
if self.parent:
return self.parent.path_from_root + [self]
return [self]

Categories

Resources