How to create a specific Binary Tree? - python

I have just implemented my first Binary Tree:
class BinaryTree:
def __init__(self, obj):
self.key = obj
self.left_c = None
self.right_c = None
def insert_left_c(self, new_node):
if self.left_c == None:
self.left_c = BinaryTree(new_node)
else:
temp = BinaryTree(new_code)
temp.left_c = self.left_c
self.left_c = temp
def insert_right_c(self, new_node):
if self.right_c == None:
self.right_c = BinaryTree(new_node)
else:
temp = BinaryTree(new_code)
temp.right_c = self.right_c
self.right_c = temp
def set_root(self, obj):
self.key = obj
def get_root(self):
return self.key
def get_left_c(self):
return self.left_c
def get_right_c(self):
return self.right_c
I am struggling to understand how you actually go about building a tree to ones specifications. As an example, I am trying to build the following tree:
However, I am really struggling to understand / visualize how you build the lower nodes and manipulate their left / right branches.
I though I may be able to do something such as:
binary_tree = BinaryTree('a')
binary_tree.insert_left_c('b')
binary_tree.insert_right_c('d')
binary_tree.insert_right_c('c')
binary_tree.insert_left_c('e')
binary_tree.insert_right_c('f')
But I realize that is nonsensical because I believe I'm creating a unique node for all letters that would be on the same level? I never actually set one to be a child of another(?).
If someone could explain how one should go about solving this, and visualizing similar problems, I would much appreciate it.

Your insert functions only operate on the root, without traversing deeper into the tree. Usually, such a function would insert into a binary search tree, recursing left or right depending on how the value to insert compares to the root of the current tree. For a general binary tree, you would want to pass an explicit list of left/right directions to specify where a new value goes.
It would be simpler to just build the tree explicitly. Start with individual trees for each leaf, then merge them.
trees = {x: BinaryTree(x) for x in 'abcdef'}
binary_tree = trees['a']
binary_tree.left_c = trees['b']
binary_tree.right_c = trees['c']
trees['b'].right_c = trees['d']
trees['c'].left_c = trees['e']
trees['c'].right_c = trees['f']

Related

Why isinstance() doesn't work as expected?

i was following this tutorial on decision trees and I tried to recreate it on my own as python project, instead of a notebook, using spyder.
I create different py files where I put different methods and classes, specifically I create a file named tree_structure with the following classes: Leaf, DecisionNode and Question. (I hope it's correct to put more classes in a single py file)
When I tried to use isinstance() in method "classify" in another py file, I was expecting True instead it returned False:
>>>leaf0
<tree_structure.Leaf at 0x11b7c3450>
>>>leaf0.__class__
tree_structure.Leaf
>>>isinstance(leaf0,Leaf)
False
>>>isinstance(leaf0,tree_structure.Leaf)
False
leaf0 was created iteratively from "build_tree" method (I just saved it to t0 for debugging.. during execution is not saved as a variable) :
t0 = build_tree(train_data)
leaf0 = t0.false_branch.false_branch
I tried also using type(leaf0) is Leaf instead of isinstance but it still returns False.
Can someone explain me why this happen?
tree_structure.py
class Question:
def __init__(self,header, column, value):
self.column = column
self.value = value
self.header = header
def match(self, example):
# Compare the feature value in an example to the
# feature value in this question.
val = example[self.column]
if is_numeric(val):
return val >= self.value
else:
return val == self.value
def __repr__(self):
# This is just a helper method to print
# the question in a readable format.
condition = "=="
if is_numeric(self.value):
condition = ">="
return "Is %s %s %s?" % (
self.header[self.column], condition, str(self.value))
class Leaf:
def __init__(self, rows):
self.predictions = class_counts(rows)
class DecisionNode:
def __init__(self,
question,
true_branch,
false_branch):
self.question = question
self.true_branch = true_branch
self.false_branch = false_branch
classifier.py
from tree_structure import Question,Leaf,DecisionNode
def classify(row, node):
# Base case: we've reached a leaf
if isinstance(node, Leaf):
print("----")
return node.predictions
# Decide whether to follow the true-branch or the false-branch.
# Compare the feature / value stored in the node,
# to the example we're considering.
if node.question.match(row):
print("yes")
return classify(row, node.true_branch)
else:
print("no")
return classify(row, node.false_branch)
build_tree
def build_tree(rows,header):
"""Builds the tree.
Rules of recursion: 1) Believe that it works. 2) Start by checking
for the base case (no further information gain). 3) Prepare for
giant stack traces.
"""
gain, question = find_best_split(rows,header)
print("--best question is ''{}'' with information gain: {}".format(question,round(gain,2)))
# Base case: no further info gain
# Since we can ask no further questions,
# we'll return a leaf.
if isinstance(rows,pd.DataFrame):
rows = rows.values.tolist()
if gain == 0:
return Leaf(rows)
# If we reach here, we have found a useful feature / value
# to partition on.
true_rows, false_rows = partition(rows, question)
# Recursively build the true branch.
print("\n----TRUE BRANCH----")
true_branch = build_tree(true_rows,header)
# Recursively build the false branch.
print("\n----FALSE BRANCH----")
false_branch = build_tree(false_rows,header)
# Return a Question node.
# This records the best feature / value to ask at this point,
# as well as the branches to follow
# dependingo on the answer.
return DecisionNode(question, true_branch, false_branch)

Append (self) with stacks in Python classes

I am doing/learning data structures and algorithms and I came across the following code:
class BinaryTree:
def __init__(self, root_data):
self.data = root_data
self.left_child = None
self.right_child = None
def inorder_iterative(self):
inorder_list = []
return inorder_list
def get_right_child(self):
return self.right_child
def get_left_child(self):
return self.left_child
def set_root_val(self, obj):
self.data = obj
def get_root_val(self):
return self.data
def preorder_iterative(self):
pre_ordered_list = [] #use this as result
stack = []
stack.append(self)
while len(stack)>0:
node = stack.pop() #should return a value
pre_ordered_list.append(node.get_root_val())
if node.right_child:
stack.append(node.get_right_child())
if node.left_child:
stack.append(node.get_left_child())
return pre_ordered_list
bn = BinaryTree(1)
bn.left_child = BinaryTree(2)
bn.right_child = BinaryTree(3)
print (bn.preorder_iterative())
I am very lost about stack.append(self) part. I am not sure what is the point of having this line and I don't fully understand the concept of .append(self). I have learnt that self represents the instance of the class.
The purpose of the stack is to simulate recursion.
The initial value placed on the stack is the tree itself (in the form of its root node). Its value is retrieved, and then each subtree is placed on the stack. On the next iteration of the loop, the left child is removed, processed, and replaced with its children, if any. The loop continues as long as there is anything on the stack to process. Once everything on the left side of the tree as been processed, you'll finally start on the right child (placed the stack way at the beginning of the loop).
Compare to a recursive version:
def preorder_recursive(self):
result = [self.get_root_val()]
if node.left_child:
result.extend(node.left_child.preorder_recursive())
if node.right_child:
result.extend(node.right_child.preorder_recursive())
return result
Each recursive call essentially puts self on a stack, allowing the left child (and its descendants) to be processed before eventually returning to the root and moving to its right child.

Implementing a depth-first tree iterator in Python

I'm trying to implement an iterator class for not-necessarily-binary trees in Python. After the iterator is constructed with a tree's root node, its next() function can be called repeatedly to traverse the tree in depth-first order (e.g., this order), finally returning None when there are no nodes left.
Here is the basic Node class for a tree:
class Node(object):
def __init__(self, title, children=None):
self.title = title
self.children = children or []
self.visited = False
def __str__(self):
return self.title
As you can see above, I introduced a visited property to the nodes for my first approach, since I didn't see a way around it. With that extra measure of state, the Iterator class looks like this:
class Iterator(object):
def __init__(self, root):
self.stack = []
self.current = root
def next(self):
if self.current is None:
return None
self.stack.append(self.current)
self.current.visited = True
# Root case
if len(self.stack) == 1:
return self.current
while self.stack:
self.current = self.stack[-1]
for child in self.current.children:
if not child.visited:
self.current = child
return child
self.stack.pop()
This is all well and good, but I want to get rid of the need for the visited property, without resorting to recursion or any other alterations to the Node class.
All the state I need should be taken care of in the iterator, but I'm at a loss about how that can be done. Keeping a visited list for the whole tree is non-scalable and out of the question, so there must be a clever way to use the stack.
What especially confuses me is this--since the next() function, of course, returns, how can I remember where I've been without marking anything or using excess storage? Intuitively, I think of looping over children, but that logic is broken/forgotten when the next() function returns!
UPDATE - Here is a small test:
tree = Node(
'A', [
Node('B', [
Node('C', [
Node('D')
]),
Node('E'),
]),
Node('F'),
Node('G'),
])
iter = Iterator(tree)
out = object()
while out:
out = iter.next()
print out
If you really must avoid recursion, this iterator works:
from collections import deque
def node_depth_first_iter(node):
stack = deque([node])
while stack:
# Pop out the first element in the stack
node = stack.popleft()
yield node
# push children onto the front of the stack.
# Note that with a deque.extendleft, the first on in is the last
# one out, so we need to push them in reverse order.
stack.extendleft(reversed(node.children))
With that said, I think that you're thinking about this too hard. A good-ole' (recursive) generator also does the trick:
class Node(object):
def __init__(self, title, children=None):
self.title = title
self.children = children or []
def __str__(self):
return self.title
def __iter__(self):
yield self
for child in self.children:
for node in child:
yield node
both of these pass your tests:
expected = ['A', 'B', 'C', 'D', 'E', 'F', 'G']
# Test recursive generator using Node.__iter__
assert [str(n) for n in tree] == expected
# test non-recursive Iterator
assert [str(n) for n in node_depth_first_iter(tree)] == expected
and you can easily make Node.__iter__ use the non-recursive form if you prefer:
def __iter__(self):
return node_depth_first_iter(self)
That could still potentially hold every label, though. I want the
iterator to keep only a subset of the tree at a time.
But you already are holding everything. Remember that an object is essentially a dictionary with an entry for each attribute. Having self.visited = False in the __init__ of Node means you are storing a redundant "visited" key and False value for every single Node object no matter what. A set, at least, also has the potential of not holding every single node ID. Try this:
class Iterator(object):
def __init__(self, root):
self.visited_ids = set()
...
def next(self):
...
#self.current.visited = True
self.visited_ids.add(id(self.current))
...
#if not child.visited:
if id(child) not in self.visited_ids:
Looking up the ID in the set should be just as fast as accessing a node's attribute. The only way this can be more wasteful than your solution is the overhead of the set object itself (not its elements), which is only a concern if you have multiple concurrent iterators (which you obviously don't, otherwise the node visited attribute couldn't be useful to you).

Traversing a binary tree and squaring each element

I'm hoping someone can help me understand binary trees for my upcoming CS course. To be more specific, I was wondering if anyone could help me on this problem: "Return a tree where all its items have been squared"
This is my class Tree:
clas Tree(object):
def __init__(self, entry, left=None, right=None):
self.entry = entry
self.left = left
self.right = right
def __repr__(self):
args = repr(self.entry)
if self.left or self.right:
args += ', {0}, {1}'.format(repr(self.left), repr(self.right))
return 'Tree({0})'.format(args)
So if I have a Tree named t, where t is defined as:
t = Tree(1,Tree(2,Tree(3)),Tree(4,Tree(5)))
I want to return t as Tree(1,Tree(4,Tree(9)),Tree(16,Tree(25)))
So I came up with this function that returns me a squared Tree, but I want to get rid of the "None"
def square_tree(tree,fn):
if(tree == None):
return tree
else:
tree.entry = fn(tree.entry)
map_tree(tree.left,fn)
map_tree(tree.right,fn)
return tree
output: Tree(4, Tree(9, Tree(16), None), Tree(25, Tree(36), None))
Any suggestions?
Trees are recursive structures. The easiest way to write tree manipulation programs is usually recursion. So think about the recursive step.
You have a tree and you want to square all the elements. So you need to:
square the root element
square all the elements in the left and right subtrees
That should be enough of a hint since it's homework...
after
t = Tree(1,Tree(2,Tree(3)),Tree(4,Tree(5)))
t is
Tree(1, Tree(2, Tree(3), None), Tree(4, Tree(5), None))
The class repr is displaying the None leafs. If you don't want it to, fix your repr.

Python; Linked list and traversing!

Starting some programming with python at school now, and I don't know how to proceed with this problem. Any thoughts?
Input consists of integer separated by line breaks. Your program should submit them in a linked list, traverse the linked list and print the highest number.
Something to take the first number, and do an action which says "if the next number is bigger, take that one, else, keep the current number, and head down the list and repeat"
Then when it gets to the end of the list, it prints the value it has.
from sys import stdin
class Kubbe:
vekt = None
neste = None
def __init__(self, vekt):
self.vekt = vekt
self.neste = None
def spor(kubbe):
# WRITE YOUR CODE HERE
# Creates linked list
forste = None
siste = None
for linje in stdin:
forrige_siste = siste
siste = Kubbe(int(linje))
if forste == None:
forste = siste
else:
forrige_siste.neste = siste
# Calls the solution function and prints the result
print spor(forste)
Input: example
54
37
100
123
1
54
Required output
123
"Linked lists" are rarely used in Python -- normally, one uses just list, the Python built-in list, which is actually more of a "dynamic vector". So, it's peculiar to see a linked list specified as part of the exercise's constraints.
But the main point is, the code you're showing is already creating a linked list -- the head is at forste, and, for each node, the next-node pointer at .neste, the payload at .vekt. So, presumably, that's not what you're asking about, no matter the text of your question.
The simple way to loop through your linked list once you have fully constructed it (i.e., at the end of the current code for spor) is
current = forste
while current is not None:
...process current.vekt...
current = current.neste
In your case, the logic for the "process" part is of course, as your Q's text already says:
if current.vekt > themax:
themax = current.vekt
The only subtlety is, you need to initially set themax, before this while loop to "the lowest possible number"; in recent versions of Python, "minus infinity" is reliably recorded and compared (though only as a float, it still compares correctly to ints), so
themax = float('-inf')
would work. More elegant might be to initially set the maximum to the first payload, avoiding messing with infinity.
Here's an answer based on your own code and language. Sorry if the new variable and function names do not translate well, as I don't speak Norwegian (Google Language Tools is my friend).
Comment: Like airplane Air Traffic Control the default language of most international programming forums such as StackOverflow is English. If you use it, you are likely to get quicker, better, and more answers -- and it probably makes the question and related answers useful to the largest number of other folks. Just my 2 øre... ;-)
from sys import stdin
class Kubbe:
vekt = None
neste = None
def __init__(self, vekt):
self.vekt = vekt
self.neste = None
def spor():
# WRITE YOUR CODE HERE
# Creates linked list
forste = None
siste = None
while True:
try:
linje = raw_input()
except EOFError:
break
forrige_siste = siste
siste = Kubbe(int(linje))
if forste == None:
forste = siste
else:
forrige_siste.neste = siste
return forste
def finne_maksimal(lenketliste):
storste = None
if lenketliste is not None:
storste = lenketliste.vekt
gjeldende = lenketliste.neste
while gjeldende is not None:
if gjeldende.vekt > storste:
storste = gjeldende.vekt
gjeldende = gjeldende.neste
return storste
lenketliste = spor()
storste = finne_maksimal(lenketliste)
if lenketliste is None:
print "tom liste"
else:
print "storste er", storste
There is a builtin function in Python called reduce, which traverses a list and "compresses" it with a given function. That is, if you have a list of five elements [a,b,c,d,e] and a function f, it will effectively do
temp = f(a,b)
temp = f( temp, c )
...
You should be able to use this to write a very neat solution.
If you want to be less abstract, you will need to iterate over each element of the list in turn, storing the greatest number so far in a variable. Change the variable only if the element you have reached is greater than the value of said variable.
This seems to work with your input (works in both python 2 and 3). Notice how max works with duck typing of Python!
This version works with Python3 also from file.
import sys
class Kubbe:
vekt = None
neste = None
def __init__(self, vekt):
self.vekt = vekt
self.neste = None
def spor():
# WRITE YOUR CODE HERE
# Creates linked list
forste = None
siste = None
while True:
linje = sys.stdin.readline().rstrip()
if not linje:
break
forrige_siste, siste = siste, Kubbe(int(linje))
if forste is None:
forste = siste
else:
forrige_siste.neste = siste
return forste
def traverse(linkedlist):
while linkedlist is not None:
yield linkedlist.vekt
linkedlist=linkedlist.neste
# Calls the solution function and prints the result
linkedlist=spor()
for item in traverse(linkedlist):
print(item)
# use builtin max:
print('Maximum is %i' % max(traverse(linkedlist)))
# if not allowed:
m = linkedlist.vekt
for item in traverse(linkedlist.neste):
if item > m: m = item
print(m)
The below code would work. The Node class represents the LinkedList Node. The LinkedList class defines the methods to add node at the end of the Linked List and find_max will traverse through the list and return the node with largest key.
class Node(object):
def __init__(self, key, next_node):
self.key = key
self.next_node = next_node
class LinkedList(object):
def __init__(self):
self.head = None
def append(self, key):
# Create a new Node
new_node = Node(key, None)
if (self.head == None):
self.head = new_node
else:
tmp = self.head
while(tmp.next_node != None):
tmp = tmp.next_node
tmp.next_node = new_node
def find_max(self):
tmp = self.head
max_num = 0
while(tmp != None):
if (tmp.key > max_num):
max_num = tmp.key
tmp = tmp.next_node
return max_num

Categories