I'm reading the following data as part of an assignment into a binary tree (not a strict binary search tree):
5
4 1 2
2 3 4
5 -1 -1
1 -1 -1
3 -1 -1
They're being read into three lists in python self.key, self.left and self.right where the first line has the integer n is the number of nodes. The next n lines are key, left, right. Where left is the key of the left child of the parent is key[left] and likewise the key of the right child is key[right], so for example the first line is the key of 4 is the root and key[1] meaning 2 is the left child of 4 and key[2] meaning 5 is the right child of 4 and so on and -1 for left and right means this key is a leaf:
Tree structure for this example
The problem is the left and right children of the root are being added but none of the children of these are being added. Am I correctly adding nodes to the tree? I cannot just add them based on value of the key because it's not a strict binary search tree as some other examples make clear, such as root = 0 and left child = 70 and right child = 20. The output of inOrder traversal is 2 4 5 (should be 1 2 3 4 5) which leads me to believe I'm not adding the further nodes. Any help on the adding methods would be appreciated...
import sys, threading
sys.setrecursionlimit(10**6) # max depth of recursion
threading.stack_size(2**27) # new thread will get stack of such size
class Node:
def __init__(self, val):
self.l = None
self.r = None
self.v = val
class Tree:
def __init__(self):
self.root = None
def getRoot(self):
return self.root
def add_root(self, val):
if(self.root is None):
self.root = Node(val)
def add_left(self, val, node):
if(node.l is None):
node.l = Node(val)
def add_right(self, val, node):
if(node.r is None):
node.r = Node(val)
def deleteTree(self):
# garbage collector will do this for us.
self.root = None
def inOrder(self):
self.result = []
if(self.root is not None):
self._inOrder(self.root, self.result)
return self.result
else:
print('root is None')
def _inOrder(self, node, result):
if(node != None):
self._inOrder(node.l, self.result)
self.result.append(node.v)
self._inOrder(node.r, self.result)
def read(self):
self.n = int(sys.stdin.readline())
self.key = [0 for i in range(self.n)]
self.left = [0 for i in range(self.n)]
self.right = [0 for i in range(self.n)]
for i in range(self.n):
[a, b, c] = map(int, sys.stdin.readline().split())
self.key[i] = a
self.left[i] = b
self.right[i] = c
#adding root
self.add_root(self.key[0])
if self.left[0] != -1:
#add left of root
self.add_left(self.key[self.left[0]], self.root)
if self.right[0] != -1:
#add right of root
self.add_right(self.key[self.right[0]], self.root)
#where it is not adding left and right nodes
for i in range(1, self.n):
if self.left[i] != -1:
# adding the other left nodes
self.add_left(self.key[self.left[i]], Node(self.key[i]))
if self.right[i] != -1:
# adding the other right nodes
self.add_right(self.key[self.right[i]], Node(self.key[i]))
def main():
tree = Tree()
tree.read()
print(" ".join(str(x) for x in tree.inOrder()))
#print(" ".join(str(x) for x in tree.preOrder()))
#print(" ".join(str(x) for x in tree.postOrder()))
threading.Thread(target=main).start()
Thanks I got it to work - I added the nodes Node(key[i]) to a dictionary and self.nodes[val] = [node, node.l, node.r] and when adding the left and recursively searched the dictionary for inOrder, preOrder and postOrder tree traversals.
class Node:
def __init__(self, val):
self.l = None
self.r = None
self.v = val
class Tree:
def __init__(self):
self.root = None
self.nodes = {}
def getRoot(self):
return self.root
def add_root(self, val):
if(self.root is None):
self.root = Node(val)
self.nodes[val] = [self.root,-1,-1]
def add_left(self, val, node):
if(node.l is None):
node.l = Node(val)
self.nodes[node.v][1] = node.l
def add_right(self, val, node):
if(node.r is None):
node.r = Node(val)
self.nodes[node.v][2] = node.r
def inOrder(self):
self.result = []
if(self.root is not None):
self._inOrder(self.root, self.result)
return self.result
else:
print('root is None')
def _inOrder(self, node, result):
if(node is not None):
try:
self._inOrder(self.nodes[node.v][1], self.result)
except (IndexError, AttributeError):
pass
self.result.append(node.v)
try:
self._inOrder(self.nodes[node.v][2], self.result)
except (IndexError, AttributeError):
pass
def preOrder(self):
self.result = []
if(self.root is not None):
self._preOrder(self.root, self.result)
return self.result
else:
print('root is None')
def _preOrder(self, node, result):
if(node is not None):
self.result.append(node.v)
try:
self._preOrder(self.nodes[node.v][1], self.result)
except (IndexError, AttributeError):
pass
try:
self._preOrder(self.nodes[node.v][2], self.result)
except (IndexError, AttributeError):
pass
def postOrder(self):
self.result = []
if(self.root is not None):
self._postOrder(self.root, self.result)
return self.result
else:
print('root is None')
def _postOrder(self, node, result):
if(node is not None):
try:
self._postOrder(self.nodes[node.v][1], self.result)
except (IndexError, AttributeError):
pass
try:
self._postOrder(self.nodes[node.v][2], self.result)
except (IndexError, AttributeError):
pass
self.result.append(node.v)
def read(self):
self.n = int(sys.stdin.readline())
self.key = [0 for i in range(self.n)]
self.left = [0 for i in range(self.n)]
self.right = [0 for i in range(self.n)]
for i in range(self.n):
[a, b, c] = map(int, sys.stdin.readline().split())
self.key[i] = a
self.left[i] = b
self.right[i] = c
#adding root
self.add_root(self.key[0])
for i in range(1, self.n):
self.nodes[self.key[i]] = [Node(self.key[i]),-1,-1]
for i in range(0, self.n):
if self.left[i] != -1:
# adding the other left nodes
self.add_left(self.key[self.left[i]], self.nodes[self.key[i]][0])
if self.right[i] != -1:
# adding the other right nodes
self.add_right(self.key[self.right[i]], self.nodes[self.key[i]][0])
Related
So this is the node part of a singly linked list. I am not supposed to change the way it has been coded, but I dont know how this type of structure would work. Self.link cannot event be accessed to point towards another part of the list. Does anyone know how to work with such a Node class?
class Node:
def __init__(self, inval=None):
self.val = inval
if inval==None:
self.link = self
print (self)
def __str__(self):
if self.val == None:
return ''
else:
return str(self.val)
def __repr__(self):
return str(self)
Here is another implementation of the linked list, which has a slightly different styled node.
class LinkedList:
lock = 0
if lock == 0:
tempdata = None
def __init__(self, *args):
self.head = Node() # Node at the head of the list
self.current = None # Node currently pointed to by the iterator
self.count = 0
def insert(self, value):
NewNode =Node(value)
NewNode.link = self.head
self.head = NewNode
self.count += 1
def __iter__(self):
self.current = self.head
return self
def __next__(self):
self.current = LinkedList.tempdata
if LinkedList.lock == 0:
self.current = self.head
LinkedList.lock += 1
else:
pass
if self.current.value == None:
LinkedList.lock = 0
raise StopIteration
previous = self.current
self.current = self.current.link
LinkedList.tempdata = self.current
return previous
def __str__(self):
result = ''
self.current = self.head
while self.current.value is not None:
if self.current.link.value is None:
result += str(self.current.value)
else:
result += str(self.current.value) + ' -> '
self.current = self.current.link
return result
def search(self, value):
found = 0
temp = None
out= False
while found == 0:
try:
temp = LinkedList.__next__(self)
if temp.value == value:
found += 1
out = temp
except StopIteration:
pass
return out
def delete(self, value):
print ("hwta")
found = 0
temp = None
head = self.head
if head.value == value:
print ("Head")
if head.link.value != None:
self.head = head.link
else:
self.head = Node()
else:
while found == 0:
try:
temp = LinkedList.__next__(self)
if temp.link.value == value:
if temp.link.link.value == None:
temp.link = Node()
break
else:
temp.link = temp.link.link
print ("tails")
break
except StopIteration:
pass
def __repr__(self):
return str(self)
#a = Node()
#print(a) # 3
#b = Node("Hullo")
#print(b) # 'Hullo'
#lst = LinkedList()
#lst.insert(2)
#lst.insert(3)
#lst.insert(5)
#lst.insert(6)
#lst.insert(7)
#lst.insert(6)
#print(lst) # 5 -> 3 -> 2
#c = lst.search(2)
#print(c) # 3
#print(c.link) # 5
#lst.insert(2)
#print(lst.head.link.link) # 3
lst.delete(6)
print (lst)
#print(next(lst)) # should print 5, 3, 2 on separate lines
#lst.delete(2)
#print(lst) # 5 -> 3
#print(len(lst)) # 2
#for u in lst:
# print(u)
Nothing in the Node implementation that would prevent you from using it in a List class. Just pretend that the final three lines of Node.__init__() don't exist.
Here is one way to use the professor's Node in your List.
class Node:
def __init__(self, inval=None):
self.val = inval
if inval==None:
self.link = self
print (self)
def __str__(self):
if self.val == None:
return ''
else:
return str(self.val)
def __repr__(self):
return str(self)
class List:
def __init__(self):
self.head = None
def prepend(self, val):
head = Node(val)
head.link = self.head
self.head = head
def append(self, val):
if self.head is None:
self.prepend(val)
else:
p = self.head
while p.link is not None:
p = p.link
p.link = Node(val)
p.link.link = None
def __str__(self):
result = '<'
p = self.head
while p is not None:
result += str(p) + ', '
p = p.link
result += '>'
return result
l = List()
l.append(3)
l.prepend(2)
l.append(4)
l.prepend(1)
l.append(5)
print(str(l))
And here is the result:
<1, 2, 3, 4, 5, >
I'm trying to implement a serializing/deserializing algorithm in python for binary trees.
Here's my code:
class Node:
count = 1
def __init__(self, value):
self.value = value
self.left = None
self.right = None
def insert(self, value):
if self.value > value:
if self.left is None:
self.left = Node(value)
Node.count += 1
else:
self.left.insert(value)
else:
if self.right is None:
self.right = Node(value)
Node.count += 1
else:
self.right.insert(value)
# Using preorder
def serialize(root, serial):
if root != None:
serial.append(root.value)
serialize(root.left, serial)
serialize(root.right, serial)
else:
serial.append('x')
def deserialize(newRoot, serial):
if serial[0] == 'x':
serial.pop(0)
else:
if len(serial) > 0:
newRoot = Node(serial.pop(0))
print(newRoot.value)
deserialize(newRoot.left, serial)
deserialize(newRoot.right, serial)
print("This program serializes a tree\n")
root = Node(3)
root.insert(1)
root.insert(2)
root.insert(4)
root.insert(5)
root.insert(0)
# Serialize
serial = []
serialize(root, serial)
print(serial)
# Deserialize
newRoot = Node(None)
deserialize(newRoot, serial)
print(newRoot.value)
The problem is, newRoot doesn't get updated by deserialize because python passes it by value. How do I get around this, preferably in the most elegant way? In C/C++, I would just pass a pointer to newRoot and it should get updated accordingly. Thanks!
You can return the newly created nodes and assign them as left and right nodes. Also poping the first element of a list is more costly than poping the last element, so reverseing the list at the beginning and then using it in the recursion will be more performant in your case. So the code will become something like:
def deserialize(serial):
serial.reverse()
return _deserialize(serial)
def _deserialize(serial):
if not serial:
return None
node = None
value = serial.pop()
if value != 'x':
node = Node(value)
node.left = _deserialize(serial)
node.right = _deserialize(serial)
return node
root = deserialize(serial)
print(root.value)
You can create left and right subtree within deserialize function and return the root.
Here is my code:
node_list = []
MARKER = -1
class Node:
def __init__(self, val):
self.val = val
self.left = None
self.right = None
def serialize(root):
if root is None:
node_list.append(MARKER)
return
node_list.append(root.val)
serialize(root.left)
serialize(root.right)
def deserialize(root, node_list):
if node_list:
val = node_list.pop(0)
else:
return
if val == MARKER:
return
# Create root, left and right recursively
root = Node(val)
root.left = deserialize(root.left, node_list)
root.right = deserialize(root.right, node_list)
return root
def inorder_traversal(root):
if root:
inorder_traversal(root.left)
print(root.val, end=' ')
inorder_traversal(root.right)
if __name__=="__main__":
# Create tree
root = Node(20)
root.left = Node(8)
root.right = Node(22)
root.left.left = Node(4)
root.left.right = Node(12)
root.left.right.left = Node(10)
root.left.right.right = Node(14)
print("Inorder traversal before serialization..")
inorder_traversal(root)
print('')
# serialize the tree and insert elements into a list
serialize(root)
print(node_list)
root1 = None
root1 = deserialize(root1, node_list)
print("Inorder traversal after deserialization..")
inorder_traversal(root1)
print('')
This is my implementation of a custom singly linked list in Python.
class SList:
def __init__(self):
self.root = None
self.size = 0
def insert(self, item):
if not item:
raise ValueError('Cannot add None item to a list')
self.size += 1
if self.root is None:
self.root = Node(item)
else:
p = Node(item)
p.next = self.root
self.root = p
"""Remove the element at the specific index"""
def remove(self, index):
if index < 0 or index >= self.size:
raise ValueError('Index cannot be negative or greater than the size of the list')
current = self.root
if index == 0:
self.root = self.root.next
else:
for _ in range(index -1):
current = current.next
p = current.next.next
if p is not None:
current.next = p
else:
current.next = None
self.size -= 1
def __len__(self):
return self.size
def __repr__(self):
res = '[ '
current = self.root
while current is not None:
res += str(current.data)
res += ' '
current = current.next
res += ']'
return res
def __iter__(self):
return self
def next(self):
........
This is the Node object
class Node:
def __init__(self, data):
try:
if not data:
raise ValueError
self.data = data
self.next = None
except ValueError:
raise ValueError('Node cannot be instantiated without an item')
I'm at a little loss at implementing the iter method. I see there are multiple ways to implement it and yield seems to be the common way forward. Would appreciate some help in implmenting it with yield
You can make your class iterable by making its __iter__ method a generator.
Here's some code that runs correctly on Python 2 or Python 3.
from __future__ import print_function
class Node(object):
def __init__(self, data):
if data is None:
raise ValueError('Node cannot be instantiated without an item')
self.data = data
self.nextnode = None
def __repr__(self):
return 'Node({})'.format(self.data)
class SList(object):
def __init__(self):
self.root = None
self.size = 0
def insert(self, item):
if item is None:
raise ValueError('Cannot add None item to a list')
self.size += 1
if self.root is None:
self.root = Node(item)
else:
p = Node(item)
p.nextnode = self.root
self.root = p
def remove(self, index):
""" Remove the element at the specific index """
if index < 0 or index >= self.size:
raise ValueError('Index cannot be negative or greater than the size of the list')
current = self.root
if index == 0:
self.root = self.root.nextnode
else:
for _ in range(index - 1):
current = current.nextnode
current.nextnode = current.nextnode.nextnode
self.size -= 1
def __len__(self):
return self.size
def __repr__(self):
res = []
current = self.root
while current is not None:
res.append(current.data)
current = current.nextnode
return str(res)
def __iter__(self):
current = self.root
while current is not None:
yield current
current = current.nextnode
# test
a = SList()
for c in 'ABCDE':
a.insert(c)
print(a)
gen = iter(a)
print('root', next(gen))
for node in gen:
print(node)
a.remove(2)
print(list(a))
for node in a:
print(node)
output
['E', 'D', 'C', 'B', 'A']
root Node(E)
Node(D)
Node(C)
Node(B)
Node(A)
[Node(E), Node(D), Node(B), Node(A)]
Node(E)
Node(D)
Node(B)
Node(A)
Try to follow this explanation:
pythontips.com/2013/09/29/the-python-yield-keyword-explained
In short and simplified form - in order to create a generator, you should create a function that contains the yield keyword once or more. Anytime yield is reached in the function execution, it is put on hold, and passes the value after the keyword to the caller.
def my_gen(arg):
yield arg * 10
for i in xrange(5):
if i / 2 == 0:
yield i
for x in my_gen(3):
print(x)
Will print:
30
0
2
4
The constructor of the Node class is also faulty, in addition to catching your own exception, you also have an error with your if condition not data will be True not only if data is False or None, but also if data is 0,an empty list, empty string and many more. Use data is None instead.
I am trying to implement binary search tree in pythonand trying to print the nodes of a tree in inorder, preorder and postorder but unfortunately my results are not correct.
Here is my code:
class Node:
def __init__(self, val):
self.v = val
self.l = None
self.r = None
class BinarySearchTree:
def __init__(self):
self.root = None
def get_root(self):
return self.root
def insert(self, val):
if self.root is None:
self.root = Node(val)
else:
self._add(val, self.root)
def _add(self, val, node):
if val < node.l:
if node.l is None:
node.l = Node(val)
else:
self._add(val, node.l)
else:
if node.r is None:
node.r = Node(val)
else:
self._add(val, node.r)
def find(self, val):
if self.root is None:
return None
else:
self._find(val, self.root)
def _find(self, val, node):
if val == node.v:
return Node
else:
if val < node.v and node is not None:
self._find(val, node.l)
if val > node.v and node is not None:
self._find(val, node.r)
def delete_tree(self):
self.root = None
def print_in_order(self): # Left, Node, Right
if self.root is None:
return None
else:
self._in_order(self.root)
def _in_order(self, node):
if node is not None:
self._in_order(node.l)
print str(node.v) + ' '
self._in_order(node.r)
def print_pre_order(self): # Node, Left, Right
if self.root is None:
return None
else:
self._pre_order(self.root)
def _pre_order(self, node):
if node is not None:
print str(node.v) + ' '
self._pre_order(node.l)
self._pre_order(node.r)
def print_post_order(self): # Left, Right, Node
if self.root is None:
return None
else:
self._post_order(self.root)
def _post_order(self, node):
if node is not None:
self._post_order(node.l)
self._post_order(node.r)
print str(node.v) + ' '
if __name__ == '__main__':
t = BinarySearchTree()
t.insert(20)
t.insert(10)
t.insert(30)
t.insert(5)
t.insert(15)
t.insert(25)
t.insert(35)
print 'In Order Traversal: \n', t.print_in_order()
print '\nPre Order Traversal: \n', t.print_pre_order()
print '\nPost Order Traversal:\n', t.print_post_order()
Can someone please tell me what am I doing wrong?
My output is in the following: Inorder and Preorder is returning the same output.
In Order Traversal:
20
10
30
5
15
25
35
None
Pre Order Traversal:
20
10
30
5
15
25
35
None
Post Order Traversal:
35
25
15
5
30
10
20
None
Traversal functions are okay. But in _add, the following comparison:
if val < node.l:
...
should be replaced with:
if val < node.v:
...
to compare new value with current node value, instead of the left node which cause wrong comparison result; results in wrong tree structure.
I am trying to practice BST tree implementation with python, following is my code,
import pdb
class Node():
def __init__(self, parent=None, key=None):
self.parent = parent if parent != None else None
self.left = None
self.right = None
self.key = key if key != None else None
class BST():
def __init__(self):
self.root = Node()
def insertKey (self, key):
#pdb.set_trace()
# transverse till we find empty position
if (self.root.key == None):
self.root.key = key
else:
node = self.root
while (node.left != None and node.right != None):
if node.key < key:
node = node.right
else:
node = node.left
#we have node either left or right is empty
if node.key < key:
node.right = Node (node, key)
else:
node.left = Node (node, key)
def inOrder (self, node):
#pdb.set_trace()
if node != None:
self.inOrder (node.left)
print node.key
self.inOrder (node.right)
def printLeft (self, node):
if node != None:
self.printLeft (node)
print node.key
def debugAll (self):
self.inOrder (self.root)
#self.printLeft (self.root)
def fromArray (self, numbers):
srt = sorted(numbers)
print srt
length = len(srt)
mid = length/2
rootEle = srt[mid]
self.insertKey (rootEle)
for i in range (1, mid+1):
try:
#pdb.set_trace()
self.insertKey (srt[mid-i])
self.insertKey (srt[mid+i])
except IndexError:
pass
bst = BST()
bst.fromArray ([1,2,4,3,6,5,10,8,9])
bst.debugAll ()
However the result of the inOrder tree walk is unexpected
1
4
5
6
10
I tried to debug through the pdb while inserting the keys, the keys are properly inserted, but when transversing the tree, some Node are skipped because they're marked as 'NoneType'. May be I am missing out on some language specifics here.
For a start, the code you have below isn't right:
while (node.left != None and node.right != None):
if node.key < key:
node = node.right
else:
node = node.left
It will stop descending if either the left or the right node doesn't exist.
EDIT: If you modify the loop like this, it works. Could be better optimized, but it's a start...
class Node():
def __init__(self, parent=None, key=None):
self.parent = parent if parent != None else None
self.left = None
self.right = None
self.key = key if key != None else None
class BST():
def __init__(self):
self.root = Node()
def insertKey (self, key):
#pdb.set_trace()
# transverse till we find empty position
if (self.root.key == None):
self.root.key = key
else:
node = self.root
while 1:
if node.key < key:
if node.right is None:
node.right = Node(node, key)
break
else:
node = node.right
else:
if node.left is None:
node.left = Node(node, key)
break
else:
node = node.left
def inOrder (self, node):
#pdb.set_trace()
if node != None:
self.inOrder (node.left)
print node.key
self.inOrder (node.right)
def printLeft (self, node):
if node != None:
self.printLeft (node)
print node.key
def debugAll (self):
self.inOrder (self.root)
#self.printLeft (self.root)
def fromArray (self, numbers):
srt = sorted(numbers)
print srt
length = len(srt)
mid = length/2
rootEle = srt[mid]
self.insertKey (rootEle)
for i in range (1, mid+1):
try:
#pdb.set_trace()
self.insertKey (srt[mid-i])
self.insertKey (srt[mid+i])
except IndexError:
pass
bst = BST()
bst.fromArray ([1,2,4,3,6,5,10,8,9])
bst.debugAll ()