Create Binary tree from list of lists in Python - python

I need to create a binary tree from a list of lists. My problem is that some of the nodes overlap(in the sense that the left child of one is the right of the other) and I want to separate them.
I duplicated the overlapping nodes and created a single list, but I am missing something. The code I use to do that:
self.root = root = BNodeItem(values[0][0], 0)
q = list()
q.append(root)
# make single tree list
tree_list = list()
tree_list.append(values[0][0])
for i in xrange(1, len(values[0])):
ll = [i for i in numpy.array(values)[:, i] if i is not None]
# duplicate the values
p = []
for item in ll[1:-1]:
p.append(item)
p.append(item)
new_ll = list()
new_ll.append(ll[0])
new_ll.extend(p)
new_ll.append(ll[-1])
tree_list.extend(new_ll)
# fix tree
for ind in xrange(len(tree_list)/2 - 1):
eval_node = q.pop(0)
eval_node.left = BNodeItem(tree_list[2*ind + 1], 0)
eval_node.right = BNodeItem(tree_list[2*ind + 2], 0)
q.append(eval_node.left)
q.append(eval_node.right)
the "values" variable looks like this(where 0 I get None normally):
100 141.9068 201.3753 285.7651 405.5200 575.4603
0 70.4688 100 141.9068 201.3753 285.7651
0 0 49.6585 70.4688 100.0000 141.9068
0 0 0 34.9938 49.6585 70.4688
0 0 0 0 24.6597 34.9938
0 0 0 0 0 17.3774
So for example the 141.9 in row = 1 has children 201.3 and 100 in row = 2, but 70.4 has children 100 and 49.6 in row 2(100 is shared).
Any suggestions?
EDIT : Had an error in len() and in creating the nodes from list values(wrong lists). Seems to still have a bug.
Seems it's working
Use this to print the tree from #Arthur's solution:
class Node():
def __init__(self, value):
self.value = value
self.leftChild = None
self.rightChild= None
def __str__(self, depth=0):
ret = ""
if self.leftChild is not None:
ret += self.leftChild.__str__(depth + 1)
ret += "\n" + (" " * depth) + str(self.value)
if self.rightChild is not None:
ret += self.rightChild.__str__(depth + 1)
return ret

Here comes a solution that return you a Node object having left and right child allowing you to use most of the tree parsing algorithms. If needed you can easily add reference to the parent node.
data2 = [[1,2,3],
[0,4,5],
[0,0,6]]
def exceptFirstColumn(data):
if data and data[0] :
return [ row[1:] for row in data ]
else :
return []
def exceptFirstLine(data):
if data :
return data[1:]
def left(data):
""" Returns the part of the data use to build the left subTree """
return exceptFirstColumn(data)
def right(data):
""" Returns the part of the data used to build the right subtree """
return exceptFirstColumn(exceptFirstLine(data))
class Node():
def __init__(self, value):
self.value = value
self.leftChild = None
self.rightChild= None
def __repr__(self):
if self.leftChild != None and self.rightChild != None :
return "[{0} (L:{1} | R:{2}]".format(self.value, self.leftChild.__repr__(), self.rightChild.__repr__())
else:
return "[{0}]".format(self.value)
def fromData2Tree(data):
if data and data[0] :
node = Node(data[0][0])
node.leftChild = fromData2Tree(left(data))
node.rightChild= fromData2Tree(right(data))
return node
else :
return None
tree = fromData2Tree(data2)
print(tree)
This code give the following result :
[1 (L:[2 (L:[3] | R:[5]] | R:[4 (L:[5] | R:[6]]]
That is the requested following tree. Test it on your data, it works. Now try to understand how it works ;)
+-----1-----+
| |
+--2--+ +--4--+
| | | |
3 5 5 6

Related

How can I find the depth of a specific node inside a binary tree?

I'm trying to figure out a recursive solution to this problem. The main thing is to return the level in the binary tree where the node is.
def find_depth(tree, node):
if node == None:
return 0
else:
return max(find_depth(tree.left))
#recursive solution here
Using this class for the values:
class Tree:
def __init__(self, value, left=None, right=None):
self.value = value
self.left = left
self.right = right
Example: Calling find_depth(tree, 7) should return the level where 7 is in the tree. (level 2)
3
/ \
7 1 <------ return that 7 is at level 2
/ \
9 3
maybe this is what you are looking for
def find_depth(tree, node):
if node is None or tree is None:
return 0
if tree == node:
return 1
left = find_depth(tree.left, node)
if left != 0:
return 1 + left
right = find_depth(tree.right, node)
if right != 0:
return 1 + right
return 0
You need to provide information about depth in find_depth call. It might look like this (assuming 0 is a sentinel informing that node is not found):
def find_depth(tree, node, depth=1):
if node == None:
return 0
if tree.value == node:
return depth
left_depth = find_depth(tree.left, node, depth+1)
right_depth = find_depth(tree.right, node, depth+1)
return max(left_depth, right_depth)
Then you call it with two parameters: x = find_depth(tree, 7).
Recursion is a functional heritage and so using it with functional style yields the best results -
base case: if the input tree is empty, we cannot search, return None result
inductive, the input tree is not empty. if tree.data matches the search value, return the current depth, d
inductive, the input tree is not empty and tree.data does not match. return the recursive result of tree.left or the recursive result of find.right
def find (t = None, value = None, d = 1):
if not t:
return None # 1
elif t.value == value:
return d # 2
else:
return find(t.left, value, d + 1) or find(t.right, value, d + 1) # 3
class tree:
def __init__(self, value, left = None, right = None):
self.value = value
self.left = left
self.right = right
t = tree \
( 3
, tree(7, tree(9), tree(3))
, tree(1)
)
print(find(t, 7)) # 2
print(find(t, 99)) # None
You can implement the find method in your tree class too
def find (t = None, value = None, d = 1):
# ...
class tree
def __init__ #...
def find(self, value)
return find(self, value)
print(t.find(7)) # 2
print(t.find(99)) # None

Creating a binary tree

I'm trying to create a tree from a flat list. I need to define a function called tree_from_flat_list. For any node at index position i, the left child is stored at index position 2*i, and the right child is stored at index position 2*i+1. :
class BinaryTree:
def __init__(self, data):
self.data = data
self.left = None
self.right = None
def get_left(self):
return self.left
def get_right(self):
return self.right
def set_left(self, tree):
self.left = tree
def set_right(self, tree):
self.right = tree
def set_data(self, data):
self.data = data
def get_data(self):
return self.data
def create_string(self, spaces):
info = ' ' * spaces + str(self.data)
if self.left != None:
info += '\n(l)' + self.left.create_string(spaces+4)
if not self.right == None:
info += '\n(r)' + self.right.create_string(spaces+4)
return info
def __str__(self):
representation = self.create_string(0)
return representation
def tree_from_flat_list(node_list):
if node_list != None:
root_index = 1
list1 = []
list2 = []
root = node_list[root_index]
left_sub_tree = list1.append(node_list[2*root_index])
right_sub_tree = list2.append(node_list[2*root_index+1])
tree = BinaryTree(root)
tree.set_left(tree_from_flat_list(left_sub_tree))
tree.set_right(tree_from_flat_list(right_sub_tree))
return tree
When I try running this:
def test():
flat_list = [None, 10, 5, 15, None, None, 11, 22]
my_tree = tree_from_flat_list(flat_list)
print(my_tree)
test()
I should get the output:
10
(l) 5
(r) 15
(l) 11
(r) 22
Edit: Still stuck on what I should be doing for the function. Any help is still appreciated.
the amount of spaces inbetween is the height of the tree and the l and r represent if they are a left child or a right child. This would looks like:
10
/ \
5 15
/ \
11 22
but instead I only get:
10
How should I edit my tree_from_flat_list function so that this works. Any help is appreciated. Thank you.
The essence of your problem is in these lines:
left_sub_tree = list1.append(node_list[2*root_index])
right_sub_tree = list2.append(node_list[2*root_index+1])
The append function sets doesn't return anything - it appends to the list. This sets your left and right sub trees to None.
The list format seems to be a variant of a binary heap where elements can be None. I think you can simplify this quite a bit:
class BinaryTree(object):
def __init__(self, label, left, right):
self.label = label
self.left = left
self.right = right
def tree_from_flat_list(ls, index=1):
if index < len(ls) and ls[index] is not None:
left = tree_from_flat_list(ls, 2*index)
right = tree_from_flat_list(ls, 2*index+1)
return BinaryTree(ls[index], left, right)
I wonder though why you don't store the left and right children in indices 2*i+1 and 2*i+2, like in a binary heap; then you don't need to have the None at the beginning.

Counting word strokes while parsing Trie tree

I'm trying to solve the keyboard autocompletion problem described here.
The problem is to calculate how many keystrokes a word requires, given some dictionary and autocomplete rules. For example, for the dictionary:
data = ['hello', 'hell', 'heaven', 'goodbye']
We get the following results (please refer to the link above for further explanations):
{'hell': 2, 'heaven': 2, 'hello': 3, 'goodbye': 1}
Quick explanation: if the user types h, then e is autocompleted because all words starting with h also have e as second letter. Now if the user types in l, the other l is filled, giving 2 strokes for the word hell. Of course, hello would require one more stroke. Please, see the link above for more examples.
My Trie code is the following, and it works fine (taken from https://en.wikipedia.org/wiki/Trie). The Stack code is to parse the tree from root (see edit below):
class Stack(object):
def __init__(self, size):
self.data = [None]*size
self.i = 0
self.size = size
def pop(self):
if self.i == 0:
return None
item = self.data[self.i - 1]
self.i-= 1
return item
def push(self, item):
if self.i >= self.size:
return None
self.data[self.i] = item
self.i+= 1
return item
def __str__(self):
s = '# Stack contents #\n'
if self.i == 0:
return
for idx in range(self.i - 1, -1, -1):
s+= str(self.data[idx]) + '\n'
return s
class Trie(object):
def __init__(self, value, children):
self.value = value #char
self.children = children #{key, trie}
class PrefixTree(object):
def __init__(self, data):
self.root = Trie(None, {})
self.data = data
for w in data:
self.insert(w, w)
def insert(self, string, value):
node = self.root
i = 0
n = len(string)
while i < n:
if string[i] in node.children:
node = node.children[string[i]]
i = i + 1
else:
break
while i < n:
node.children[string[i]] = Trie(string[:i], {})
node = node.children[string[i]]
i = i + 1
node.value = value
def find(self, key):
node = self.root
for char in key:
if char in node.children:
node = node.children[char]
else:
return None
return node
I couldn't figure it out how to count the number of strokes:
data = ['hello', 'hell', 'heaven', 'goodbye']
tree = PrefixTree(data)
strokes = {w:1 for w in tree.data} #at least 1 stroke is necessary
And here's the code to parse the tree from the root:
stack = Stack(100)
stack.push((None, pf.root))
print 'Key\tChilds\tValue'
print '--'*25
strokes = {}
while stack.i > 0:
key, curr = stack.pop()
# if something:
#update strokes
print '%s\t%s\t%s' % (key, len(curr.children), curr.value)
for key, node in curr.children.items():
stack.push((key, node))
print strokes
Any idea or constructive comment would help, thanks!
Edit
Great answer by #SergiyKolesnikov. There's one small change that can be done in order to avoid the call to endsWith(). I just added a boolean field to the Trie class:
class Trie(object):
def __init__(self, value, children, eow):
self.value = value #char
self.children = children #{key, trie}
self.eow = eow # end of word
And at the end of insert():
def insert(self, string, value):
#...
node.value = value
node.eow = True
Then just replace curr.value.endswith('$'): with curr.eow. Thank you all!
The trie for your example can look like this
' '
| \
H G
| |
E O
| \ |
L A O
| | |
L$ V D
| | |
O E B
| |
N Y
|
E
What nodes in the trie can be seen as markers for user key strokes? There are two types of such nodes:
Inner nodes with more than one child, because the user has to choose among multiple alternatives.
Nodes that represent the last letter of a word, but are not leaves (marked with $), because the user has to type the next letter if the current word is not what is needed.
While traversing the trie recursively one counts how many of these marker nodes were encountered before the last letter of a word was reached. This count is the number of strokes needed for the word.
For the word "hell" it is two marker nodes: ' ' and E (2 strokes).
For the word "hello" it is three marker nodes: ' ', E, L$ (3 strokes).
And so on...
What needs to be changed in your implementation:
The end of a valid word needs to be marked in the tree, so that the second condition can be checked. Therefore, we change the last line of the PrefixTree.insert() method from
node.value = value
to
node.value = value + '$'
Now we add a stroke counter for each stack item (the last value in the triple pushed to the stack) and the checks that increase the counter:
stack = Stack(100)
stack.push((None, tree.root, 0)) # We start with stroke counter = 0
print('Key\tChilds\tValue')
print('--'*25)
strokes = {}
while stack.i > 0:
key, curr, stroke_counter = stack.pop()
if curr.value is not None and curr.value.endswith('$'):
# The end of a valid word is reached. Save the word and the corresponding stroke counter.
strokes[curr.value[:-1]] = stroke_counter
if len(curr.children) > 1:
# Condition 2 is true. Increase the stroke counter.
stroke_counter += 1
if curr.value is not None and curr.value.endswith('$') and len(curr.children) > 0:
# Condition 1 is true. Increase the stroke counter.
stroke_counter += 1
print('%s\t%s\t%s' % (key, len(curr.children), curr.value))
for key, node in curr.children.items():
stack.push((key, node, stroke_counter)) # Save the stroke counter
print(strokes)
Output:
Key Childs Value
--------------------------------------------------
None 2 None
h 1
e 2 h
a 1 he
v 1 hea
e 1 heav
n 0 heaven$
l 1 he
l 1 hell$
o 0 hello$
g 1
o 1 g
o 1 go
d 1 goo
b 1 good
y 1 goodb
e 0 goodbye$
{'heaven': 2, 'goodbye': 1, 'hell': 2, 'hello': 3}
While you go through your stack, you should keep a stroke counter for each node:
It begins at 0 for None.
If the current node has more than 2 children, the counter of the
children will be 1 more than the current counter.
If the current value is a valid word and has at least one child, the
counter of the child(ren) will be 1 more than the current counter.
For documentation purpose, here's my Ruby answer :
class Node
attr_reader :key, :children
attr_writer :final
def initialize(key, children = [])
#key = key
#children = children
#final = false
end
def final?
#final
end
end
class Trie
attr_reader :root
def initialize
#root = Node.new('')
end
def add(word)
node = root
word.each_char.each{|c|
next_node = node.children.find{|child| child.key == c}
if next_node then
node = next_node
else
next_node = Node.new(c)
node.children.push(next_node)
node = next_node
end
}
node.final = true
end
def count_strokes(node=root,word="",i=0)
word=word+node.key
strokes = {}
if node.final? then
strokes[word]=i
if node.children.size>0 then
i+=1
end
elsif node.children.size>1 then
i+=1
end
node.children.each{|c|
strokes.merge!(count_strokes(c, word, i))
}
strokes
end
end
data = ['hello', 'hell', 'heaven', 'goodbye']
trie = Trie.new
data.each do |word|
trie.add(word)
end
# File.readlines('/usr/share/dict/british-english').each{|line|
# trie.add line.strip
# }
puts trie.count_strokes
#=> {"hell"=>2, "hello"=>3, "heaven"=>2, "goodbye"=>1}
60 lines only, and it take less than 3 seconds for 100 000 words.

Maximum sum in a non-binary tree in Python

I have a non-binary tree and each node of that tree has a value. I would like to get the maximum sum available.
For example:
10
9 8 7
1 2 5 5 15
The return would be 10+7+15=32
I know how to do this if the tree was binary, but what if the tree has n branches?
This code is the binary one taken from the first answer of this question: Find the maximum sum of a tree in python
Assuming each node has a value attribute and a children attribute which is either a list of child nodes, an empty list, or None:
def tree_sum(node):
if node.children:
child_sums = []
for child in node.children:
child_sums.append(tree_sum(child) + node.value)
return max(child_sums)
else:
return node.value
print tree_sum(root)
Here's one approach:
class Node:
def __init__(self, value):
self.value = value
self.children = []
def max_sum(root):
if len(root.children) == 0:
return root.value
sums = []
for child in root.children:
sums.append(root.value + max_sum(child))
return max(sums)
n_9 = Node(9)
n_9.children.extend([Node(1), Node(2), Node(5)])
n_8 = Node(8)
n_8.children.extend([Node(5)])
n_7 = Node(7)
n_7.children.extend([Node(15)])
n_10 = Node(10)
n_10.children = [n_9, n_8, n_7]
print max_sum(n_10)
# Output: 32

error in converting linked list to a single number in python

here this is the node definition
class Node(object):
def __init__(self,value=None):
self.value = value
self.next = None
this is the conversion for the code a number to linked list
def number_to_list(number):
head,tail = None,None
p = True
for x in str(number):
if x=='-':
p = False
continue
else:
if p:
node = Node(int(x))
else:
node = Node(int("-"+x))
if head:
tail.next = node
else:
head = node
tail = node
return head
pass
this is code for conversion of linked list to number
def list_to_number(head):
neg = False
num = ''
for number in head:
val = str(number)
if (val.find('-')!= -1):
neg = True
num=num+val.replace('-','')
if (neg==False):
return int(num)
else:
return -1*int(num)
pass
here it is the test cases
def test_number_to_list():
import listutils
head = number_to_list(120)
assert [1,2,0] == listutils.from_linked_list(head)
assert 120 == list_to_number(head)
head = number_to_list(0)
assert [0] == listutils.from_linked_list(head)
assert 0 == list_to_number(head)
head = number_to_list(-120)
assert [-1, -2, 0] == listutils.from_linked_list(head)
assert -120 == list_to_number(head)
here from_linked_list means
# avoids infinite loops
def from_linked_list(head):
result = []
counter = 0
while head and counter < 100: # tests don't use more than 100 nodes, so bail if you loop 100 times.
result.append(head.value)
head = head.next
counter += 1
return result
at last in this the problem is while converting the linked list to single number it is encountering an error i.e.,node object is not iterable
please help me out of this to write the code
def list_to_number(head):
neg = False
num = ''
for number in head:
val = str(number)
TypeError: 'Node' object is not iterable
here this is the traceback
The
for number in head:
is not a correct way to iterate of the list.
You need to start from head and then follow the chain of next references.
Note that if __iter__ is defined on Node like this:
class Node(object):
def __init__(self,value=None):
self.value = value
self.next = None
def __iter__(self):
that = self
while that is not None:
yield that.value
that = that.next
Then:
for number in head:
Would actually work.

Categories

Resources