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

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.

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)

Trying to add a preorder traversal method to my class

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

Is it possible to catch empty nested attributes in python?

I'm trying to create a custom object that supports nested attributes.
I need to implement a specific kind of search.
If an attribute doesn't exist at the lowest level, I want to recurse and see if the attribute exists at a higher level.
I've spent all day trying to do this. The closest I've come is being able to print the attribute search path.
class MyDict(dict):
def __init__(self):
super(MyDict, self).__init__()
def __getattr__(self, name):
return self.__getitem__(name)
def __getitem__(self, name):
if name not in self:
print name
self[name] = MyDict()
return super(MyDict, self).__getitem__(name)
config = MyDict()
config.important_key = 'important_value'
print 'important key is: ', config.important_key
print config.random.path.to.important_key
Output:
important key is: important_value
random
path
to
important_key
{}
What I need to happen is instead to see if important_key exists at the lowest level (config.random.path.to), then go up a level (config.random.path) and only return None if it doesn't exist at the top level.
Do you think this is possible?
Thank you so much!
Yes, it's possible. In your search routine, recur to the end of the path, checking for the desired attribute. At the bottom level, return the attribute if found, None otherwise. At each non-terminal level, recur to the next level down.
if end of path # base case
if attribute exists here
return attribute
else
return None
else # some upper level
exists_lower = search(next level down)
if exists_lower
return exists_lower
else
if attribute exists here
return attribute
else
return None
Does this pseudo code get you moving toward a solution?

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 ""

Inverse of hasattr in Python

hasattr(obj, attribute) is used to check if an object has the specified attribute but given an attribute is there a way to know where (all) it is defined?
Assume that my code is getting the name of an attribute (or a classmethod) as string and I want to invoke classname.attribute but I don't have the classname.
One solution that comes to my mind is this
def finder(attr):
for obj in globals():
try:
if globals()[obj].__dict__[attr]:
return(globals()[obj])
except:
...
usage:
class Lime(object):
#classmethod
def lfunc(self):
print('Classic')
getattr(finder('lfunc'),'lfunc')() #Runs lfunc method of Lime class
I am quite sure that this is not the best (oe even proper way) to do it. Can someone please provide a better way.
It is always "possible". Wether it is desirable is another history.
A quick and dirty way to do it is to iterate linearly over all classes and check if any define the attribute you have. Of course, that is subject to conflicts, and it will yield the first class that has such a named attribute. If it exists in more than one, it is up to you to decide which you want:
def finder(attr):
for cls in object.__subclasses__():
if hasattr(cls, attr):
return cls
raise ValueError
Instead of searching in "globals" this searches all subclasses of "object" - thus the classes to be found don't need to be in the namespace of the module where the finder function is.
If your methods are unique in teh set of classes you are searching, though, maybe you could just assemble a mapping of all methods and use it to call them instead.
Let's suppose all your classes inehrit from a class named "Base":
mapper = {attr_name:getattr(cls, attr_name) for cls in base.__subclasses__() for attr_name, obj in cls.__dict__.items()
if isinstance(obj, classmethod) }
And you call them with mapper['attrname']()
This avoids a linear search at each method call and thus would be much better.
- EDIT -
__subclassess__ just find the direct subclasses of a class, not the inheritance tree - so it won't be usefull in "real life" - maybe it is in the specifc case the OP has in its hands.
If one needs to find things across a inheritance tree, one needs to recurse over the each subclass as well.
As for old-style classes: of course this won't work - that is one of the motives for which they are broken by default in new code.
As for non-class attributes: they can only be found inspecting instances anyway - so another method has to be thought of - does not seem to be the concern of the O.P. here.
This might help:
import gc
def checker(checkee, maxdepth = 3):
def onlyDict(ls):
return filter(lambda x: isinstance(x, dict), ls)
collection = []
toBeInspected = {}
tBI = toBeInspected
gc.collect()
for dic in onlyDict(gc.get_referrers(checkee)):
for item, value in dic.iteritems():
if value is checkee:
collection.append(item)
elif item != "checker":
tBI[item] = value
def _auxChecker(checkee, path, collection, checked, current, depth):
if current in checked: return
checked.append(current)
gc.collect()
for dic in onlyDict(gc.get_referents(current)):
for item, value in dic.iteritems():
currentPath = path + "." + item
if value is checkee:
collection.append(currentPath)
else:
try:
_auxChecker(checkee, currentPath, collection,
checked, value, depth + 1)
if depth < maxdepth else None
except TypeError:
continue
checked = []
for item, value in tBI.iteritems():
_auxChecker(checkee, item, collection, checked, value, 1)
return collection
How to use:
referrer = []
class Foo:
pass
noo = Foo()
bar = noo
import xml
import libxml2
import sys
import os
op = os.path
xml.foo = bar
foobar = noo
for x in checker(foobar, 5):
try:
y= eval(x)
referrer.append(x)
except:
continue
del x, y
ps: attributes of the checkee will not be further checked, for recursive or nested references to the checkee itself.
This should work in all circumstances, but still needs a lot of testing:
import inspect
import sys
def finder(attr, classes=None):
result = []
if classes is None:
# get all accessible classes
classes = [obj for name, obj in inspect.getmembers(
sys.modules[__name__])]
for a_class in classes:
if inspect.isclass(a_class):
if hasattr(a_class, attr):
result.append(a_class)
else:
# we check for instance attributes
if hasattr(a_class(), attr):
result.append(a_class)
try:
result += finder(attr, a_class.__subclasses__())
except:
# old style classes (that don't inherit from object) do not
# have __subclasses; not the best solution though
pass
return list(set(result)) # workaround duplicates
def main(attr):
print finder(attr)
return 0
if __name__ == "__main__":
sys.exit(main("some_attr"))

Categories

Resources