I want to print my binary tree vertical and the nodes should be random numbers, but output that I get is not what I want.
For example I receive something like this:
497985
406204
477464
But program should print this:
.....497985
406204
.....477464
I don't know where is the problem. Im begginer at programming so if anyone can help me it would be great.
from numpy.random import randint
import random
from timeit import default_timer as timer
class binarytree:
def __init__(self):
self.elem = 0
self.left = None
self.right = None
def printtree(tree, h):
if tree is not None:
printtree(tree.right, h+1)
for i in range(1, h):
print(end = ".....")
print(tree.elem)
printtree(tree.left, h+1)
def generate(tree, N, h):
if N == 0:
tree = None
else:
tree = binarytree()
x = randint(0, 1000000)
tree.elem = int(x)
generate(tree.left, N // 2, h)
generate(tree.right, N - N // 2 - 1, h)
printtree(tree, h)
tree = binarytree()
generate(tree, 3, 0)
I've re-written your code to be a little more Pythonic, and fixed what appeared
to be some bugs:
from random import randrange
class BinaryTree:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
#classmethod
def generate_random_tree(cls, depth):
if depth > 0:
return cls(randrange(1000000),
cls.generate_random_tree(depth - 1),
cls.generate_random_tree(depth - 1))
return None
def __str__(self):
"""
Overloaded method to format tree as string
"""
return "\n".join(self._format())
def _format(self, cur_depth=0):
"""
Format tree as string given current depth. This is a generator of
strings which represent lines of the representation.
"""
if self.right is not None:
yield from self.right._format(cur_depth + 1)
yield "{}{}".format("." * cur_depth, self.val)
if self.left is not None:
yield from self.left._format(cur_depth + 1)
print(BinaryTree.generate_random_tree(4))
print()
print(BinaryTree(1,
BinaryTree(2),
BinaryTree(3,
BinaryTree(4),
BinaryTree(5))))
This outputs a tree, which grows from the root at the middle-left to leaves at
the right:
...829201
..620327
...479879
.746527
...226199
..463199
...498695
987559
...280755
..168727
...603817
.233132
...294525
..927571
...263402
..5
.3
..4
1
.2
Here it's printed one random tree, and one tree that I manually constructed.
I've written it so that the "right" subtree gets printed on top - you can switch
this around if you want.
You can make some further adjustments to this by making more dots at once (which
I think was your h parameter?), or adapting bits into whatever program
structure you want.
This code works because it makes sure it builds a whole tree first, and then
later prints it. This clear distinction makes it easier to make sure you're
getting all of it right. Your code was a little confused in this regard - your
generate function did instantiate a new BinaryTree at each call, but you
never attached any of them to each other! This is because when you do
tree = ... inside your function, all you're doing is changing what the local
name tree points to - it doesn't change the attribute of the tree from higher
up that you pass to it!
Your generate also calls printtree every time, but printtree also calls
itself... This just doesn't seem like it was entirely right.
In my program, this bit generates the random tree:
def generate_random_tree(cls, depth):
if depth > 0:
return cls(randrange(1000000),
cls.generate_random_tree(depth - 1),
cls.generate_random_tree(depth - 1))
return None
The classmethod bit is just some object-oriented Python stuff that isn't very
important for the algorithm. The key thing to see is that it generates two new
smaller trees, and they end up being the left and right attributes of the
tree it returns. (This also works because I did a little re-write of
__init__).
This bit basically prints the tree:
def _format(self, cur_depth=0):
"""
Format tree as string given current depth. This is a generator of
strings which represent lines of the representation.
"""
if self.right is not None:
yield from self.right._format(cur_depth + 1)
yield "{}{}".format("." * cur_depth, self.val)
if self.left is not None:
yield from self.left._format(cur_depth + 1)
It's a generator of lines - but you could make it directly print the tree by
changing each yield ... to print(...) and removing the yield froms. The
key things here are the cur_depth, which lets the function be aware of how
deep in the tree it currently is, so it knows how many dots to print, and the
fact that it recursively calls itself on the left and right subtrees (and you
have to check if they're None or not, of course).
(This part is what you could modify to re-introduce h).
Related
I want to implement a Binary Tree in Python. I sumit my code. What I would like to do is to
set the height of the Binary Tree with the variable L. But, when I implement the code, it seems that the code has created a Binary Tree that is greater than I expected.
I arrive to this conclusion because when I set the height as 1 and I do print(node.right.right.right), I still get 1.
class Tree:
def __init__(self,x,left=None,right=None):
self.x=x
self.left=left
self.right=right
def one_tree(self,node):
node=Tree(1)
node.right=Tree(1)
node.left=Tree(1)
return node
node=Tree(1)
node=node.one_tree(node)
L=1
while L>0:
node=node.one_tree(node)
node.left=node
node.right=node
L=L-1
print(node.right.right.right.right)
I found a problem with your code. one_tree method overwrites the argument node itself.
class Tree:
def __init__(self, x, left=None, right=None):
self.x = x
self.left = left
self.right = right
def one_tree(self, node):
node = Tree(1) # This assignment statement overwrites the argument 'node'.
node.right = Tree(1)
node.left = Tree(1)
return node
one_tree method gets an argument node but the first line of this method overwrites it like this node = Tree(1). Whatever the method gets as an argument, the method always has a new instance of Tree as node variable.
Several issues:
one_tree doesn't use the node that you pass as argument, so whatever you pass to it, the returned tree will always have 3 nodes (a root with 2 children).
one_tree is a method that doesn't use self, so it really should be a class method, not an instance method
If the intended algorithm was to add a level above the already created tree, and have the new root's children reference the already existing tree, then you would need to only create one node, not three, and let the two children be the given node.
Not a problem, but your loop is not really the "python way" to loop L times. Use range instead.
This means your code could be this:
class Tree:
def __init__(self, x, left=None, right=None):
self.x = x
self.left = left
self.right = right
node = Tree(1)
L = 1
for _ in range(L):
node = Tree(1, node, node)
Now you should still be careful with this tree, as it only has L+1 unique node instances, where all "nodes" on the same level are actually the same node instance. All the rest are references that give the "impression" of having a tree with many more nodes. Whenever you start mutating nodes in that tree, you'll see undesired effects.
If you really need separate node instances for all nodes, then the algorithm will need to be adapted. You could then use recursion:
def create(height):
if height == 0: # base case
return Tree(1)
return Tree(1, create(height-1), create(height-1))
L = 1
node = create(L)
The problem is about solving max depth of a binary tree using recursion. originally from leetcode https://leetcode.com/problems/maximum-depth-of-binary-tree/solution/
I'm trying to understand the code by walking through a real example. root = 3, left child = 9, right child = null. should return 2.
Specifically, I don't quite understand how left_height would get int value of 1. I understand that right_height is None, therefore 0.
It would be great someone can walk through the example with the real value. I understand the algorithm well. I'm not very familiar with manipulating of python objects.
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def maxDepth(self, root):
"""
:type root: TreeNode
:rtype: int
"""
if root is None:
return 0
else:
left_height = self.maxDepth(root.left)
right_height = self.maxDepth(root.right)
return max(left_height, right_height) + 1
The left node has no further left or right, so it'll return max(0,0)+1, or 1
This call comes back up the tree to the root to return max(1,0)+1, and the final result is 2
I followed the link, these numbers are irrelevant so
3
/ \
9 20
/ \
15 7
is the same as
.
/ \
. .
/ \
. .
I am trying to perform an inorder traversal of a tree. The code itself feels right, except it is not working properly. I have a feeling it has to either do with the if condition, how append works in python, or something perhaps with return. This works correctly if I use print instead of return, I think, but I want to be able to use return and still get the correct answer. For example, for the tree [1,None,2,3], my code returns [1] which is clearly incorrect.
Additionally is it possible to solve this problem using list comprehension? If so, any sample code would be greatly appreciated.
Here is my code:
class Solution(object):
def inorderTraversal(self, root):
res = []
if root:
self.inorderTraversal(root.left)
res.append(root.val)
self.inorderTraversal(root.right)
return res
Also before marking this as a duplicate, I know in order traversals have been asked on Stackoverflow (plenty of times), but none of them helped me understand why my understanding is wrong. I would be so grateful if someone helped me learn how to correct my approach versus simply posting another link without explanation. Thank you so much!
The reason this doesn't work is that res only has the value of the first node you give it appended to it; each time you recursively recall the function, it just makes a new res. It is a simple fix though, as follows:
class Solution(object):
def inorderTraversal(self, root):
res = []
if root:
res = self.inorderTraversal(root.left)
res.append(root.val)
res = res + self.inorderTraversal(root.right)
return res
In this, it returns the left branch, the value, and then the right. This can be done much more briefly as follows:
class Solution(object):
def inorderTraversal(self, root):
return (self.inorderTraversal(root.left) + [root.val] + self.inorderTraversal(root.right)) if root else []
Use this instead , a simple recursion ::
class Node:
def __init__(self,key):
self.left = None
self.right = None
self.val = key
def printInorder(root):
if root:
printInorder(root.left)
print(root.val)
printInorder(root.right)
def printPostorder(root):
if root:
printPostorder(root.left)
printPostorder(root.right)
print(root.val)
def printPreorder(root):
if root:
print(root.val)
printPreorder(root.left)
printPreorder(root.right)
# Driver code
root = Node(1)
root.left = Node(2)
root.right = Node(3)
root.left.left = Node(4)
root.left.right = Node(5)
print "Preorder traversal of binary tree is"
printPreorder(root)
print "\nInorder traversal of binary tree is"
printInorder(root)
print "\nPostorder traversal of binary tree is"
printPostorder(root)
Source :: here
#Benedict Randall Shaw's answer is already perfect. I just want to add some fun to it in a pythonic way. Although the doc does not suggest using a mutable object as default parameter, this will somewhat simplify the code by treating the default mutable list as a class member of the python function.
The difference is only the += is replaced by =, since the res is always the same list object inside the function before the function object is garbage collected.
def inorderTraversal(root, res=[]):
if root:
res = inorderTraversal(root.left)
res.append(root.val)
res = inorderTraversal(root.right)
return res
Yet another approach to output a list, the advantage being that you need to add values only to a single list:
def inorder(root):
return_list = []
def innerInOrder(root):
if root == None:
return
innnerInOrder(root.left)
return_list.append(root.data)
innerInOrder(root.right)
innerInOrder(root)
return return_list
You could just declare the list outside the function so that it does not create a new list everytime you call the function ( since it's a recursive function), but you could use other approaches posted. :-)
I have just introduced myself to oop and binary trees in Python, but I ran into problems while I tried to implement the max depth method. It does not seem to give me the right answer, it gives me 1 whereas the number should be much bigger or perhaps I'm completely misunderstanding something. I added a fraction of my code below
class Node:
def __init__(self, value, left=None, right=None):
self.left = left
self.right = right
self.value = value
self.count = 1
def depth(self):
if self.left:
left_depth = self.left.depth()
else:
left_depth = 0
right_depth = self.right.depth() if self.right else 0
print(max(left_depth, right_depth) + 1)
tree = createTree(words) # list of words
tree.depth()
print(max(left_depth, right_depth) + 1)
should be...
return max(left_depth, right_depth) + 1
so that your .depth() method actually returns a value when called.
Then, at the end when you actually want a result:
print(tree.depth())
Also, it's a bit odd that you're using two different if-else constructs.
left_depth = self.left.depth() if self.left else 0
right_depth = self.right.depth() if self.right else 0
would work just fine and be more concise.
As an exercise I'm trying to encode some symbols using Huffman trees, but using my own class instead of the built in data types with Python.
Here is my node class:
class Node(object):
left = None
right = None
weight = None
data = None
code = ''
length = len(code)
def __init__(self, d, w, c):
self.data = d
self.weight = w
self.code = c
def set_children(self, ln, rn):
self.left = ln
self.right = rn
def __repr__(self):
return "[%s,%s,(%s),(%s)]" %(self.data,self.code,self.left,self.right)
def __cmp__(self, a):
return cmp(self.code, a.code)
def __getitem__(self):
return self.code
and here is the encoding function:
def encode(symbfreq):
tree = [Node(sym,wt,'') for sym, wt in symbfreq]
heapify(tree)
while len(tree)>1:
lo, hi = sorted([heappop(tree), heappop(tree)])
lo.code = '0'+lo.code
hi.code = '1'+hi.code
n = Node(lo.data+hi.data,lo.weight+hi.weight,lo.code+hi.code)
n.set_children(lo, hi)
heappush(tree, n)
return tree[0]
(Note, that the data field will eventually contain a set() of all the items in the children of a node. It just contains a sum for the moment whilst I get the encoding correct).
Here is the previous function I had for encoding the tree:
def encode(symbfreq):
tree = [[wt, [sym, ""]] for sym, wt in symbfreq]
heapq.heapify(tree)
while len(tree)>1:
lo, hi = sorted([heapq.heappop(tree), heapq.heappop(tree)], key=len)
for pair in lo[1:]:
pair[1] = '0' + pair[1]
for pair in hi[1:]:
pair[1] = '1' + pair[1]
heapq.heappush(tree, [lo[0] + hi[0]] + lo[1:] + hi[1:])
return sorted(heapq.heappop(tree)[1:], key=lambda p: (len(p[-1]), p))
However I've noticed that my new procedure is incorrect: it gives the top nodes the longest codewords instead of the final leaves, and doesn't produce the same tree for permutations of input symbols i.e. the following don't produce the same tree (when run with new encoding function):
input1 = [(1,0.25),(0,0.25),(0,0.25),(0,0.125),(0,0.125)]
input2 = [(0,0.25),(0,0.25),(0,0.25),(1,0.125),(0,0.125)]
I'm finding I'm really bad at avoiding this kind of off-by-one/ordering bugs - how might I go about sorting this out in the future?
There's more than one oddity ;-) in this code, but I think your primary problem is this:
def __cmp__(self, a):
return cmp(self.code, a.code)
Heap operations use the comparison method to order the heap, but for some reason you're telling it to order Nodes by the current length of their codes. You almost certainly want the heap to order them by their weights instead, right? That's how Huffman encoding works.
def __cmp__(self, a):
return cmp(self.weight, a.weight)
For the rest, it's difficult to follow because 4 of your 5 symbols are the same (four 0 and one 1). How can you possibly tell whether it's working or not?
Inside the loop, this is strained:
lo, hi = sorted([heappop(tree), heappop(tree)])
Given the repair to __cmp__, that's easier as:
lo = heappop(tree)
hi = heappop(tree)
Sorting is pointless - the currently smallest element is always popped. So pop twice, and lo <= hi must be true.
I'd say more ;-), but at this point I'm confused about what you're trying to accomplish in the end. If you agree __cmp__ should be repaired, make that change and edit the question to give both some inputs and the exact output you're hoping to get.
More
About:
it gives the top nodes the longest codewords instead of the final leaves,
This isn't an "off by 1" thing, it's more of a "backwards" thing ;-) Huffman coding looks at nodes with the smallest weights first. The later a node is popped from the heap, the higher the weight, and the shorter its code should be. But you're making codes longer & longer as the process goes on. They should be getting shorter & shorter as the process goes on.
You can't do this while building the tree. In fact the codes aren't knowable until the tree-building process has finished.
So, rather than guess at intents, etc, I'll give some working code you can modify to taste. And I'll include a sample input and its output:
from heapq import heappush, heappop, heapify
class Node(object):
def __init__(self, weight, left, right):
self.weight = weight
self.left = left
self.right = right
self.code = None
def __cmp__(self, a):
return cmp(self.weight, a.weight)
class Symbol(object):
def __init__(self, name, weight):
self.name = name
self.weight = weight
self.code = None
def __cmp__(self, a):
return cmp(self.weight, a.weight)
def encode(symbfreq):
# return pair (sym2object, tree), where
# sym2object is a dict mapping a symbol name to its Symbol object,
# and tree is the root of the Huffman tree
sym2object = {sym: Symbol(sym, w) for sym, w in symbfreq}
tree = sym2object.values()
heapify(tree)
while len(tree) > 1:
lo = heappop(tree)
hi = heappop(tree)
heappush(tree, Node(lo.weight + hi.weight, lo, hi))
tree = tree[0]
def assigncode(node, code):
node.code = code
if isinstance(node, Node):
assigncode(node.left, code + "0")
assigncode(node.right, code + "1")
assigncode(tree, "")
return sym2object, tree
i = [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5)]
s2o, t = encode(i)
for v in s2o.values():
print v.name, v.code
That prints:
a 010
c 00
b 011
e 11
d 10
So, as hoped, the symbols with the highest weights have the shortest codes.
I suspect the problem is in segment: -
lo.code = '0'+lo.code
hi.code = '1'+hi.code
both hi & low can be intermediate nodes where as you need to update the codes at the leaves where the actual symbols are. I think you should not maintain any codes at construction of the huffman tree but get the codes of individual symbols after the construction of huffman tree by just traversing.
Heres my pseudo code for encode: -
tree = ConstructHuffman(); // Same as your current but without code field
def encode(tree,symbol):
if tree.data == symbol :
return None
else if tree.left.data.contains(symbol) :
return '0' + encode(tree.left,symbol)
else :
return '1' + encode(tree.right,symbol)
Calculate codes for all symbol using above encode method and then u can use them for encoding.
Note: Change comparision function from comparing codes to comparing weights.