Here is the Class named BNode,
class BNode:
def __init__(self, value=None, left=None, right=None):
self.value = value
self.left = left
self.right = right
def __repr__(self):
return '' % (self.value, self.left, self.right)
and print out below
>>> root = BNode('root')
>>> root.left = BNode('left')
>>> root.right = BNode('right')
>>> root.left.left = BNode('left-left')
>>> root.left.right = BNode('left=right')
>>> print root
root (
left (
left-left (
None
None)
left-right (
None
None))
right (
None
None))
Q) Modify the Class, so that the result like below could be made.
root (
left (
left-left (
None
None)
left-right (
None
None))
right (
None
None))
and my answer is the following one.
class BNode:
def __init__(self, value=None, left=None, right=None):
self.value = value
self.left = left
self.right = right
def __repr__(self, level=0):
R = ''
for ele in range(level):
R += '\t'
R += str(self.value)
R += ' ('
R += '\n'
if isinstance(self.left, BNode):
R += BNode.__repr__(self.left, level+1)
else:
for ele in range(level+1):
R += '\t'
R += str(self.left)
R += '\n'
if isinstance(self.right, BNode):
R += BNode.__repr__(self.right, level+1)
else:
for ele in range(level+1):
R += '\t'
R += str(self.right)
R += ')'
return R
But I want to know if it is the best solution for this question.
I think there is much nicer one...
Is there some efficient way?
Thanks in advance ~ :)
First, I'd kill the kwarg on __repr__ - as a dundermethod, it's code path should be exclusively for handling repr() calls, etc. Just move the current code to a .format_node() (or w/e) method that has the kwarg, with __repr__ kicking it off with level=0.
Also, check out the textwrap stdlib module - with the right mix of subsequent_indent, drop_whitespace, and super-large width kwargs, it might be able to do what you need, but the source is among the more accessible of the stdlib modules, check it out for some ideas on the general approach.
http://docs.python.org/2/library/textwrap.html#textwrap.TextWrapper
http://hg.python.org/cpython/file/80e9cb6163b4/Lib/textwrap.py
You're using a recursive method, which is good.
However, you're not using methods correctly - you don't need to call them as BNode.__repr__(self.left, level+1). Instead, you can do: self.left.__repr__(level+1)
Likewise, to create a sequence filled with the same item, instead of an explicit loop, you can use *: '\t'*level
In general, python has a number of string manipulation facilities which you'll find useful: http://docs.python.org/2/library/string.html
Finally, you might like to create a separate tree-oriented map method to do the traversal, and separately write the function which does the work. See: http://rosettacode.org/wiki/Tree_traversal#Python
You can and should clean up your code with these changes.
Related
so I have been working on this class project implementing a binary search tree. The professor wants us to make the private recursive while make the public one simple. (like when to insert_element(50), it calls a private function recursive_insert(50, self.__root) to solve).
My insertion function runs for no error yet the test case always return empty, and here are my codes for the private functions:
class Binary_Search_Tree:
class __BST_Node:
def __init__(self, value):
self.value = value
self.left=None
self.right=None
def __init__(self):
self.__root = None
self.__height=0
self.__size=0
def _in_order_str(self, root):
if root is None:
outcome= "[ ]"
elif self.__size==1:
outcome = "[ " + str(root.value) + " ]"
else:
outcome = "[ "
self._in_order_str(root.left)
outcome += str(root.value) +", "
self._in_order_str(root.right)
outcome+= " ]"
return outcome
def _recur_ins(self, val,root):
if root is None:
root=Binary_Search_Tree.__BST_Node(val)
elif root.value>val:
root.left = _recur_ins(val,root.left) #do I need self here?
elif root.value <val:
root.right = _recur_ins(val,root.right)
return root
And this one is for the public:
def insert_element(self, value):
self._recur_ins(value,self.__root)
self.__size+=1
My Test Case:
def test_insertion_from_empty(self):
root=None
self.__bst.insert_element(50)
self.__bst.insert_element(30)
self.__bst.insert_element(70)
self.assertEqual('[ 30, 50, 70 ]', self.__bst.in_order())
UPDATE: I think the problem comes from my _in_order_str(self, root): method. The general case I found online is:
def inorder(root):
if root is not None:
inorder(root.left)
print root.key
inorder(root.right)
I know this could be a very silly question, but I really failed to figure it our by myself. Any help will be appreciated so thank you so much!!!
After changing your code as little as possible, I think I have managed to get it working.
from pprint import pprint # For debugging
class Binary_Search_Tree:
class __BST_Node:
def __init__(self, value):
self.value = value
self.left = None
self.right = None
def __init__(self):
self.__root = None
self.__height = 0
self.__size = 0
def __in_order_str(self, root):
if root is None:
outcome = "[ ]"
elif self.__size == 1:
outcome = "[ " + str(root.value) + " ]"
else:
outcome = "[ "
self.__in_order_str(root.left)
outcome += str(root.value) + ", "
self.__in_order_str(root.right)
outcome += " ]"
return outcome
def __recur_ins(self, val, root):
if root is None:
root = Binary_Search_Tree.__BST_Node(val)
elif root.value > val:
root.left = self.__recur_ins(val, root.left)
elif root.value < val:
root.right = self.__recur_ins(val, root.right)
return root
def insert_element(self, value):
self.__root = self.__recur_ins(value, self.__root)
self.__size += 1
def test_insertion_from_empty(self):
self.insert_element(50)
self.insert_element(60)
self.insert_element(70)
# self.assertEqual('[ 30, 50, 70 ]', self.__bst.in_order())
test = Binary_Search_Tree()
test.test_insertion_from_empty()
pprint(vars(test))
Notes on the changes:
changed some functions(_recur_ins, _in_order_str) from using '_' to '__' to make them private functions. I did it based on Python Official Documentation, private functions use at least two leading underscores and at most one trailing underscore.
First line in insert_element, added 'self.__root= ' so that the returned root value will be stored as the new root
Added 'self.' in front of '__recur_ins', since as far as I know, you must use self whenever you need to call a function which is located at the same class.
I did not modify anything much in __in_order_str, since I think the author only asked for the insertion (?)
commented assertEqual, since no function is provided in the question (?)
Modified the spaces so that it can be more readable
If I put the debug mode right before I dumped the variable, this is what I get:
Which I think should be correct. 50 is inserted first, thus it is used as the root, then 60 is inserted on the right child of 50, and 70 is put on the right child of 60.
Note: I'm also just a novice, please tell me any mistakes that I have done and I will rectify it :)
Below code is a simple implementation of BFS in Python. I able to print the values level by level from a tree. However when I want to search a element and print it . I am not able to do it. Whts is the error?
def search_bfs(self,root,key):
q=QueueClass()
q.enqueue(root)
while q.size() > 0:
curr_node = q.dequeue()
#print curr_node
#print key
if curr_node == key:
print curr_node
break
if curr_node.left is not None:
q.enqueue(curr_node.left)
if curr_node.right is not None:
q.enqueue(curr_node.right)
from QueueClass import QueueClass
class Node:
def __init__(self,data):
self.data=data
self.left=None
self.right=None
def __str__(self):
return str(self.data)
class searchtree:
def __init__(self):
self.root = None
def create(self,val):
if self.root == None:
self.root=Node(val)
else:
current=self.root
while 1:
if val < current.data:
if current.left:
current=current.left
else:
current.left=Node(val)
break
if val > current.data:
if current.right:
current=current.right
else:
current.right=Node(val)
break
else:
break
tree=searchtree()
lst=[3,1,2,6,4,5,8,12]
for i in lst:
tree.create(i)
tree.search_bfs(tree.root, 3)
You really make it hard to reproduce your problem! So here's what I did:
class QueueClass(object):
def __init__(self):
self.l = []
def size(self): return len(self.l)
def enqueue(self, it): self.l.append(it)
def dequeue(self): return self.l.pop()
class Node:
def __init__(self, name, left=None, right=None):
self.name = name
self.left = left
self.right = right
def __str__(self):
return '{}:{}/{}'.format(self.name, self.left, self.right)
root = Node('root')
adding all the code you omitted (more than you supplied!-).
And now, adding your code exactly as reported, the call:
search_bfs(None, root, root)
emits
root:None/None
exactly as desired and contrary to your report.
It follows that your bug is in some of code you didn't show us, not in the coded you did show.
You either have a buggy queue-class, or are building a different tree than you thought, or searching for a node that is not actually in the tree.
Hard to debug code you're now showing, you know.
Added: so now I've integrated the extra code per your edit and at the end I have:
st = searchtree()
st.create('imtheroot')
st.search_bfs(st.root, st.root)
and of course it prints imtheroot as expected.
Is your bug perhaps STILL hiding in parts you're not yet showing, e.g instead of looking for a node you may be looking for something else?
E.g, if the final call was erroneously st.search_bfs(st.root, 'imtheroot') then obviously the search would fail -- you're checking equality of the key parameter with a node, so key clearly must be a node. not a string or other things (unless the Node class defines a very, very peculiar __eq__ method, which the one you've shown fortunately doesn't:-).
I think the issue is that when you do if curr_node == key, curr_node is a Node object, which has an integer .data attribute, but key is the integer value.
So I think you just need to use if curr_node.data == key.
How do I make a function that returns the number of nodes in a tree that have two children?
My class code is as follows:
class RefBinaryTree:
def __init__(self, data, left=None, right=None):
self.key = data
self.left = left
self.right = right
def insert_left(self, value):
self.left = RefBinaryTree(value, left=self.left)
def insert_right(self, value):
self.right = RefBinaryTree(value, right=self.right)
def get_left_subtree(self):
return self.left
def get_right_subtree(self):
return self.right
def set_value(self, new_value):
self.key = new_value
def get_value(self):
return self.key
def create_string(self, indent):
string = str(self.key) + '---+'
if self.left:
string += '\n(l)' + indent + self.left.create_string(indent + ' ')
if self.right:
string += '\n(r)' + indent + self.right.create_string(indent + ' ')
return string
def __str__(self):
return self.create_string(' ')
I'm guessing it would be best to use recursion. Any hints or helpful links would be awesome. Thanks.
It's really quite simple to count two-child nodes recursively. If you return a number with each function call (zero as the base case) you can simply add 1 every time you find a two-child node:
def findDoubleNodes(tree):
if tree == None or (tree.left == None and tree.right == None):
# base case
return 0
elif tree.left <> None and tree.right <> None:
# both have children, so add one to our total and go down one level
return findDoubleNodes(tree.left)+findDoubleNodes(tree.right) + 1
else:
# only one child, so only go down one level
return findDoubleNodes(tree.left)+findDoubleNodes(tree.right)
Inputting a RefBinaryTree returns the number of nodes with two children. An example:
x = RefBinaryTree(1)
x.insert_left(5)
x.left.insert_left(6)
x.left.insert_right(7)
x.left.right.insert_left(8)
x.left.right.insert_right(9)
x.left.right.right.insert_right(10)
The (lazily) created tree looks like this:
1
/
5
/ \
6 7
/ \
8 9
\
10
And findDoubleNodes(x) returns 2, as only two nodes (5 and 7) have two children.
Additionally, adding a left child to node 9 (x.left.right.right.insert_left(11)) has the expected result, returning 3.
This should do:
def countNodes(tree):
if tree is None:
return 0
left = tree.get_left_subtree()
rght = tree.get_right_subtree()
return (0 if left is None or rght is None else 1) \
+ countNodes(left) + countNodes(rght)
I programmed a Trie as a class in python. The search and insert function are clear, but now i tried to programm the python function __str__, that i can print it on the screen. But my function doesn't work!
class Trie(object):
def __init__(self):
self.children = {}
self.val = None
def __str__(self):
s = ''
if self.children == {}: return ' | '
for i in self.children:
s = s + i + self.children[i].__str__()
return s
def insert(self, key, val):
if not key:
self.val = val
return
elif key[0] not in self.children:
self.children[key[0]] = Trie()
self.children[key[0]].insert(key[1:], val)
Now if I create a Object of Trie:
tr = Trie()
tr.insert('hallo', 54)
tr.insert('hello', 69)
tr.insert('hellas', 99)
And when i now print the Trie, occures the problem that the entries hello and hellas aren't completely.
print tr
hallo | ellas | o
How can i solve that problem?.
Why not have str actually dump out the data in the format that it is stored:
def __str__(self):
if self.children == {}:
s = str(self.val)
else:
s = '{'
comma = False
for i in self.children:
if comma:
s = s + ','
else:
comma = True
s = s + "'" + i + "':" + self.children[i].__str__()
s = s + '}'
return s
Which results in:
{'h':{'a':{'l':{'l':{'o':54}}},'e':{'l':{'l':{'a':{'s':99},'o':69}}}}}
There are several issues you're running into. The first is that if you have several children at the same level, you'll only be prefixing one of them with the initial part of the string, and just showing the suffix of the others. Another issue is that you're only showing leaf nodes, even though you can have terminal values that are not at a leaf (consider what happens when you use both "foo" and "foobar" as keys into a Trie). Finally, you're not outputting the values at all.
To solve the first issue, I suggest using a recursive generator that does the traversal of the Trie. Separating the traversal from __str__ makes things easier since the generator can simply yield each value we come across, rather than needing to build up a string as we go. The __str__ method can assemble the final result easily using str.join.
For the second issue, you should yield the current node's key and value whenever self.val is not None, rather than only at leaf nodes. As long as you don't have any way to remove values, all leaf nodes will have a value, but we don't actually need any special casing to detect that.
And for the final issue, I suggest using string formatting to make a key:value pair. (I suppose you can skip this if you really don't need the values.)
Here's some code:
def traverse(self, prefix=""):
if self.val is not None:
yield "{}:{}".format(prefix, self.val)
for letter, child in self.children.items():
yield from child.traverse(prefix + letter)
def __str__(self):
return " | ".join(self.traverse())
If you're using a version of Python before 3.3, you'll need to replace the yield from statement with an explicit loop to yield the items from the recursive calls:
for item in child.traverse(prefix + letter)
yield item
Example output:
>>> t = Trie()
>>> t.insert("foo", 5)
>>> t.insert("bar", 10)
>>> t.insert("foobar", 100)
>>> str(t)
'bar:10 | foo:5 | foobar:100'
You could go with a simpler representation that just provides a summary of what the structure contains:
class Trie:
def __init__(self):
self.__final = False
self.__nodes = {}
def __repr__(self):
return 'Trie<len={}, final={}>'.format(len(self), self.__final)
def __getstate__(self):
return self.__final, self.__nodes
def __setstate__(self, state):
self.__final, self.__nodes = state
def __len__(self):
return len(self.__nodes)
def __bool__(self):
return self.__final
def __contains__(self, array):
try:
return self[array]
except KeyError:
return False
def __iter__(self):
yield self
for node in self.__nodes.values():
yield from node
def __getitem__(self, array):
return self.__get(array, False)
def create(self, array):
self.__get(array, True).__final = True
def read(self):
yield from self.__read([])
def update(self, array):
self[array].__final = True
def delete(self, array):
self[array].__final = False
def prune(self):
for key, value in tuple(self.__nodes.items()):
if not value.prune():
del self.__nodes[key]
if not len(self):
self.delete([])
return self
def __get(self, array, create):
if array:
head, *tail = array
if create and head not in self.__nodes:
self.__nodes[head] = Trie()
return self.__nodes[head].__get(tail, create)
return self
def __read(self, name):
if self.__final:
yield name
for key, value in self.__nodes.items():
yield from value.__read(name + [key])
Instead of your current strategy for printing, I suggest the following strategy instead:
Keep a list of all characters in order that you have traversed so far. When descending to one of your children, push its character on the end of its list. When returning, pop the end character off of the list. When you are at a leaf node, print the contents of the list as a string.
So say you have a trie built out of hello and hellas. This means that as you descend to hello, you build a list h, e, l, l, o, and at the leaf node you print hello, return once to get (hell), push a, s and at the next leaf you print hellas. This way you re-print letters earlier in the tree rather than having no memory of what they were and missing them.
(Another possiblity is to just descend the tree, and whenever you reach a leaf node go to your parent, your parent's parent, your parent's parent's parent... etc, keeping track of what letters you encounter, reversing the list you make and printing that out. But it may be less efficient.)
Me and my friend are doing some school work with programming in Python 3.1 and are VERY stuck. We're programming a binary tree and it's working fine except when we want to print all the nodes in inorder in a way that would create a sentence (all the words in inorder just after one another in a row). We have been looking all over the internet for clues as to how to procede and we've been working with this little thing for like two hours. Any advice/help would be awesome.
Our program/Binary tree:
class Treenode:
def __init__(self, it = None, le = None, ri = None):
self.item = it
self.left = le
self.right = ri
class Bintree:
def __init__(self):
self.item = None
self.left = None
self.right = None
def put(self, it = None):
key = Treenode(it)
if self.item == None:
self.item = key
return
p = self.item
while True:
if key.item < p.item:
if p.left == None:
p.left = key
return
else:
p = p.left
elif key.item > p.item:
if p.right == None:
p.right = key
return
else:
p = p.right
else:
return
def exists(self, it):
key = it
p = self.item
if p == key:
return True
while True:
if key < p.item:
if p.left == None:
return False
else:
p = p.left
elif key > p.item:
if p.right == None:
return False
else:
p = p.right
else:
return
def isEmpty(self):
if self.item == None:
return True
else:
return False
def printtree (Treenode):
if Treenode.left != None:
printtree (Treenode.left)
print (Treenode.item)
if Treenode.right != None:
printtree (Treenode.right)
We get a sort of print when we run the program which looks like this: "bintree.Treenode object at 0x02774CB0", which is not what we want.
We use the tree by running this:
import bintree
tree = bintree.Bintree()
print(tree.isEmpty()) # should give True
tree.put("solen")
print(tree.isEmpty()) # should give False
tree.put("gott")
tree.put("sin")
tree.put("hela")
tree.put("ban")
tree.put("upp")
tree.put("himlarunden")
tree.put("manen")
tree.put("seglar")
tree.put("som")
tree.put("en")
tree.put("svan")
tree.put("uti")
tree.put("midnattsstuden")
print(tree.exists("visa")) # should give False
print(tree.exists("ban")) # should give True
tree.printtree() # print sorted
Also, the second last row gives us "None" instead of "True", which is wierd.
To print a binary tree, if you are printing a leaf you just print the value; otherwise, you print the left child then the right child.
def print_tree(tree):
if tree:
print tree.value
print_tree(tree.left)
print_tree(tree.right)
print(tree.exists("visa")) returns None, because in the last line of exists() there's return statement without any value (which defaults to None).
Also you shouldn't name a printtree argument Treenode since it's a name of an existing class and that might lead to confusion. It should look more like:
def printtree(tree_node):
if tree_node.left is not None:
printtree(tree_node.left)
print(tree_node.item)
if tree_node.right is not None:
printtree(tree_node.right)
Another thing is calling printtree - it's a function, not Bintree method, so I suppose you should call it printtree(tree).
One way to make testing easier is to use -assert()- instead of printing things and then referring back to your code.
tree = Bintree()
assert(tree.isEmpty())
tree.put("solen")
assert(not tree.isEmpty())
tree.put("gott")
tree.put("sin")
tree.put("hela")
tree.put("ban")
http://docs.python.org/reference/simple_stmts.html#the-assert-statement
It raises an error if its condition is not true. I know that doesn't fix your bug but making things less ambiguous always helps debugging.
You are not specifying a starting case for printtree(). You're defining how to recurse through your tree correctly, but your call to printtree() has no node to start at. Try setting a default check to see if a parameter is passed in, and if one isn't start at the head node of the bintree.
The reason your second to last line is printing None is because, in your exists method, you just have a "return", rather than a "return True", for the case of finding a `p.item' that is equal to key.