0

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)

2
  • You dont every increment h .. so the range function inside printtree is range(1,0) or range(1,1)`` in either case the resulting ranges are zero length so the print(end=".....") is never called Commented Dec 11, 2019 at 13:52
  • Hello! Your code seems to be a bit confused, currently. You've got a number of unused imports, and generate is overwriting its tree argument every time you call it - you aren't actually recursively building a tree but you're recursively building lots of singleton trees, and printing all of those. Also it's not very clear to me what the output you're looking for is - could you elaborate at all on how you want the tree to be formatted? (Is the tree growing from the left to the right?) Commented Dec 11, 2019 at 13:54

1 Answer 1

1

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).

Sign up to request clarification or add additional context in comments.

4 Comments

ok thank you ! but can you make some futher explanations? i mean i dont think i get whats happening in this code and still it doesnt print what it should becouse all the nodes are pretty much the same.
Hi @sonia! Can you clarify what it "should" print please? It's not yet very clear to me from your question, I'm afraid! Maybe you could add a bigger example output?
at each level, your algorithm generates the same numbers. for example if our random numbers are 1,2,3,4,5,6. first line of the output should be: .....5 second: ..........6 third:1 fourth: ..........4 and so on .....2 and ..........3 , numbers or nodes in printed tree cant be doubled .
Hello again @sonia - you're absolutely right, that wasn't correct behaviour - I'd just written a massive bug, where I was just printing the left subtree twice instead of the left and then the right subtree. I've (hopefully) fixed this and added a little more explanation. Let me know what you'd like me to clarify more!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.