I have this test code on Binary Tree:
def test_deleteMin_root(self):
btree = BinaryTree()
min_value = self.person('AAKVIK', 'ANNE-MARIT', 'RISØYVEGEN 17', '1705', 'SARPSBORG')
node = BinaryTreeNode(min_value)
btree.insert(value = min_value)
btree.insert(value = self.person('Zero', 'Zero', 'Zero street', '1234', 'ZeroCity'))
btree.deleteMin()
self.assertEqual(node, btree.findMin())
I get this failure result:
======================================================================
FAIL: test_deleteMin_root (__main__.BinaryTreeTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Users\abdka\Documents\Programs\Python\PythonExercises\aicourse\test_binarytree.py", line 47, in test_deleteMin_root
self.assertEqual(node, btree.findMin())
AssertionError: <BinaryTreeNode.BinaryTreeNode object at 0x000001C7E33EFA00> != <BinaryTreeNode.BinaryTreeNode object at 0x000001C7EAB5A6D0>
When I change AssertEqual to AssertNotEqual in the last line of the test code (and that's the only thing I change):
def test_deleteMin_root(self):
btree = BinaryTree()
min_value = self.person('AAKVIK', 'ANNE-MARIT', 'RISØYVEGEN 17', '1705', 'SARPSBORG')
node = BinaryTreeNode(min_value)
btree.insert(value = min_value)
btree.insert(value = self.person('Zero', 'Zero', 'Zero street', '1234', 'ZeroCity'))
btree.deleteMin()
self.assertNotEqual(node, btree.findMin())
I get this failure:
======================================================================
FAIL: test_deleteMin_root (__main__.BinaryTreeTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Users\abdka\Documents\Programs\Python\PythonExercises\aicourse\test_binarytree.py", line 47, in test_deleteMin_root
self.assertNotEqual(node, btree.findMin())
AssertionError: <BinaryTreeNode.BinaryTreeNode object at 0x000001C7EE3D4F10> == <BinaryTreeNode.BinaryTreeNode object at 0x000001C7E5DCAA00>
When I assert equal, it says they're not equal, and when I assert not equal, it says they're equal. I don't understand; what's the error here? How can I fix it?
Here's the full test code, BinaryTree code and BinaryTreeNode code:
Binary Tree code:
from BinaryTreeNode import BinaryTreeNode
class BinaryTree:
def __init__(self, data = None):
self._root = None
if isinstance(data, BinaryTreeNode):
self._root = data
def findLeftMost(self, treenode):
left = treenode.left
if left == None:
return treenode
return self.findLeftMost(left)
def findMin(self):
return self.findLeftMost(self._root)
def findRightMost(self, treenode):
right = treenode.right
if right == None:
return treenode
return self.findRightMost(right)
def findMax(self):
return self.findRightMost(self._root)
def find(self, key, treenode = None):
if treenode == None:
treenode = self._root
if treenode == None:
return None
elif treenode.value > key:
if treenode.left:
return self.find(key, treenode.left)
elif treenode.value < key:
if treenode.right:
return self.find(key, treenode.right)
elif treenode.value == key:
return treenode
else:
raise KeyError("Key not found")
def _getnodes(self, current = None, treenode = None, value = None):
if current != None and treenode != None:
return current, treenode
if value == None:
if treenode == None:
raise Exception("Attempt to insert an empty space into Binary Tree")
else:
if treenode.value == None:
raise Exception("Attempt to insert an Node into Binary Tree with no key value")
else:
if treenode != None:
if treenode.value != None:
raise Exception("Key inconsistency detected")
else:
treenode = BinaryTreeNode(value)
if current == None:
current = self._root
return current, treenode
def insert(self, current = None, treenode = None, value = None):
if current == None:
current = self._root
# Checking consistency ...
current, treenode = self._getnodes(current, treenode, value)
if current != None:
if treenode.value < current.value:
treenode.level += 1
if current.left is None:
current.left = treenode
else:
self.insert(current.left, treenode)
elif treenode.value > current.value:
treenode.level += 1
if current.right is None:
current.right = treenode
else:
self.insert(current.right, treenode)
else:
if self._root == None:
treenode.level = 0
self._root = treenode
else:
raise Exception("Duplicate key: " + treenode.value)
else: # If empty tree, the first node entered is the root
self._root = treenode
return treenode
def deleteMin(self):
parent = self._root
while True:
# If a left branch exists - find the smallest item
current = parent.left
if current:
if current.left == None:
if current.right != None:
parent.left = current.right
return current
else:
parent.left = None
return current
else:
parent = current
# If no left branch exists, the root item is the smallest in the tree
else:
self._root = parent.right
return self._root
def deleteMax(self):
parent = self._root
while True:
current = parent.right
if current.right == None:
if current.left != None:
parent.right = current.left
return current
else:
parent.right = None
return current
else:
parent = current
def delete(self, key):
node = self.find(key)
delnode = node
if not node.left and not node.right:
node = None
elif node.right:
temptree = BinaryTree(node.right)
mintempnode = temptree.deleteMin()
node.value = mintempnode.value
elif node.left:
node = node.left
return delnode
Binary Tree Node code:
class BinaryTreeNode:
def __init__(self, value,
lefttree = None,
righttree = None):
self.value = value
self.left = lefttree
self.right = righttree
self.level = 0
# Bruker setter/getters
#property
def value(self):
return self.__value
#value.setter
def value(self, value):
self.__value = value
#property
def left(self):
return self.__left
#left.setter
def left(self, lefttree):
self.__left = lefttree
#property
def right(self):
return self.__right
#right.setter
def right(self, righttree):
self.__right = righttree
#property
def level(self):
return self.__level
#level.setter
def level(self, level):
self.__level = level
def __str__(self):
return self.value
def hasRight(self):
if self.right == None:
return False
return True
#return self.right != None
def hasLeft(self):
if self.left == None:
return False
return True
#return self.left != None
def prefixOrder(self):
print(str(self.value), ' ')
if self.hasLeft():
self.left.prefixOrder()
if self.hasRight():
self.right.prefixOrder()
def infixOrder(self):
if self.hasLeft():
self.left.infixOrder()
print(str(self.value), ' ')
if self.hasRight():
self.right.infixOrder()
def postfixOrder(self):
if self.hasLeft():
self.left.postfixOrder()
if self.hasRight():
self.right.postfixOrder()
print(str(self.value), ' ')
def levelOrder(self):
from queue import SimpleQueue
FIFOQueue = SimpleQueue()
FIFOQueue.put(self)
self.levelOrderEntry(FIFOQueue)
while not FIFOQueue.empty():
node = FIFOQueue.get()
print(str(node.value), ' ')
def levelOrderEntry(self, queue):
if queue.empty():
return
node = queue.get()
print(str(node.value), ' ')
if node.hasLeft():
queue.put(node.left)
if node.hasRight():
queue.put(node.right)
if node.hasLeft() or node.hasRight:
self.levelOrderEntry(queue)
def __eq__(self, other):
if other != None:
return self.value == other.value
elif other == None and self.value == None:
return True
return False
def __ne__(self, other):
if other != None:
if self.value == None:
return False
else:
return not self.value != other.value
return True
def __lt__(self, other):
if other != None:
return self.value < other.value
elif other == None and self.value == None:
return False
return False
def __le__(self, other):
if other != None:
return self.value <= other.value
elif other == None and self.value == None:
return False
return False
def __gt__(self, other):
if other != None:
return self.value > other.value
elif other == None and self.value == None:
return False
return False
def __ge__(self, other):
if other != None:
return self.value >= other.value
elif other == None and self.value == None:
return False
return False
The full test code:
import unittest
from BinaryTree import BinaryTree
from BinaryTreeNode import BinaryTreeNode
from collections import namedtuple
class BinaryTreeTest(unittest.TestCase):
def setUp(self):
self.person = namedtuple('person', ['lastname', 'firstname', 'address',
'postalcode', 'city'])
persons_file = open("Personer-kort.dta", 'r')
content = persons_file.read()
content = content.splitlines()
self.binarytree = BinaryTree()
for p in content:
self.binarytree.insert(value = self.person(*p.split(';')))
persons_file.close()
def test_findMin(self):
min_value = self.person('AAKVIK', 'ANETTE', 'BAKLIEN 11', '1360', 'NESBRU')
node = BinaryTreeNode(min_value)
self.assertEqual(node, self.binarytree.findMin())
def test_findMax(self):
max_value = self.person('ØYFOSS', 'ØISTEIN', 'ORHEIM 76', '0367', 'OSLO')
node = BinaryTreeNode(max_value)
self.assertEqual(node, self.binarytree.findMax())
def test_deleteMin(self):
self.binarytree.deleteMin()
min_value = self.person('AAKVIK', 'ANNE-MARIT', 'RISØYVEGEN 17', '1705', 'SARPSBORG')
node = BinaryTreeNode(min_value)
self.assertEqual(node, self.binarytree.findMin())
def test_deleteMin_root(self):
btree = BinaryTree()
min_value = self.person('AAKVIK', 'ANNE-MARIT', 'RISØYVEGEN 17', '1705', 'SARPSBORG')
node = BinaryTreeNode(min_value)
btree.insert(value = min_value)
btree.insert(value = self.person('Zero', 'Zero', 'Zero street', '1234', 'ZeroCity'))
btree.deleteMin()
self.assertNotEqual(node, btree.findMin())
def test_deleteMax(self):
self.binarytree.deleteMax()
max_value = self.person('ØYFOSS', 'WERNER STENVOLD', 'KIRKVOLL 28', '5935', 'LAVIK')
node = BinaryTreeNode(max_value)
self.assertEqual(node, self.binarytree.findMax())
def test_find(self):
value = self.person('SKARSHAUG','ASBJØRN HARALD', 'ALAPMO 72', '7290', 'STØREN')
node = BinaryTreeNode(value)
self.assertEqual(node, self.binarytree.find(value))
def test_find_key_not_found(self):
value = self.person('BORIS','JOHNSON', 'SOME STREET 72', '1234', 'LONDON')
self.assertEqual(None, self.binarytree.find(value))
self.assertRaises(KeyError, self.binarytree.find, value)
def test_delete(self):
value = self.person('SKARSHAUG','ASBJØRN HARALD', 'ALAPMO 72', '7290', 'STØREN')
node = BinaryTreeNode(value)
self.assertEqual(node, self.binarytree.find(value))
self.binarytree.delete(value)
self.assertEqual(None, self.binarytree.find(value))
def test_insert_value(self):
value1 = self.person('WIKILUND','JOHAN', 'SVETUN 11', '8510', 'NARVIK')
node1 = BinaryTreeNode(value1)
value2 = self.person('ALFRED', 'POLLEN', 'gate 11', '1234', 'KONGSBERG')
node2 = BinaryTreeNode(value2)
self.binarytree.insert(value=value1)
self.binarytree.insert(value=value2)
self.assertEqual(node1, self.binarytree.find(value1))
self.assertEqual(node2, self.binarytree.find(value2))
def test_insert_node(self):
value1 = self.person('WIKILUND','JOHAN', 'SVETUN 11', '8510', 'NARVIK')
node1 = BinaryTreeNode(value1)
value2 = self.person('ALFRED', 'POLLEN', 'gate 11', '1234', 'KONGSBERG')
node2 = BinaryTreeNode(value2)
self.binarytree.insert(treenode=node1)
self.binarytree.insert(treenode=node2)
self.assertEqual(node1, self.binarytree.find(value1))
self.assertEqual(node2, self.binarytree.find(value2))
def test_insert_duplicate(self):
value = self.person('SKARSHAUG','ASBJØRN HARALD', 'ALAPMO 72', '7290', 'STØREN')
self.assertRaisesRegex(Exception, "Duplicate key", self.binarytree.insert, [None, None, value])
def test_insert_empty_space(self):
self.assertRaisesRegex(Exception, "Attempt to insert an empty space into Binary Tree",
self.binarytree.insert, [None, None, None])
def test_insert_empty_node(self):
node = BinaryTreeNode(None)
self.assertRaisesRegex(Exception, "Attempt to insert an Node into Binary Tree with no key value",
self.binarytree.insert, [None, node, None])
def test_find_in_empty_tree(self):
tree = BinaryTree()
value = self.person('SKARSHAUG','ASBJØRN HARALD', 'ALAPMO 72', '7290', 'STØREN')
self.assertEqual(None, tree.find(value))
if __name__ == '__main__':
import sys;sys.argv = ['', 'BinaryTreeTest']
unittest.main()
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 build a binary tree with python code, now I could print it in order with testTree.printInorder(testTree.root). I have tried to lookup some node ,and the function findNode doesn't work anymore . print testTree.findNode(testTree.root,20) whatever I put in just return None.
class TreeNode:
def __init__(self, value):
self.left = None;
self.right = None;
self.data = value;
class Tree:
def __init__(self):
self.root = None
def addNode(self,node,value):
if node == None:
self.root = TreeNode(value)
else:
if value < node.data:
if node.left == None:
node.left = TreeNode(value)
else:
self.addNode(node.left,value)
else:
if node.right == None:
node.right = TreeNode(value)
else:
self.addNode(node.right,value)
def printInorder(self,node):
if node != None:
self.printInorder(node.left)
print node.data
self.printInorder(node.right)
def findNode(self,node,value):
if self.root != None:
if value == node.data:
return node.data
elif value < node.data and node.left != None:
self.findNode(node.left,value)
elif value > node.data and node.right != None:
self.findNode(node.right,value)
else:
return None
testTree = Tree()
testTree.addNode(testTree.root, 200)
testTree.addNode(testTree.root, 300)
testTree.addNode(testTree.root, 100)
testTree.addNode(testTree.root, 30)
testTree.addNode(testTree.root, 20)
#testTree.printInorder(testTree.root)
print testTree.findNode(testTree.root,20)
Any function without an explicit return will return None.
You have not returned the recursive calls within findNode. So, here.
if value == node.data:
return node.data
elif value < node.data and node.left != None:
return self.findNode(node.left,value)
elif value > node.data and node.right != None:
return self.findNode(node.right,value)
Now, I can't help but thinking this is a bit noisy. You'll always start adding from the root, yes?
testTree.addNode(testTree.root, 200)
You could rather do this
testTree.addNode(200)
And to do that, you basically implement your methods on the TreeNode class instead. So, for the addNode.
You could also "return up" from the recursion, rather than "pass down" the nodes as parameters.
class TreeNode:
def __init__(self, value):
self.left = None
self.right = None
self.data = value
def addNode(self,value):
if self.data == None: # Ideally, should never end-up here
self.data = value
else:
if value < self.data:
if self.left == None:
self.left = TreeNode(value)
else:
self.left = self.left.addNode(value)
else:
if self.right == None:
self.right = TreeNode(value)
else:
self.right = self.right.addNode(value)
return self # Return back up the recursion
Then, in the Tree class, just delegate the addNode responsibility to the root
class Tree:
def __init__(self):
self.root = None
def addNode(self,value):
if self.root == None:
self.root = TreeNode(value)
else:
self.root = self.root.addNode(value)
When you recurse to children in findNode you need to return the result, otherwise the function will implicitly return None:
def findNode(self,node,value):
if self.root != None:
if value == node.data:
return node.data
elif value < node.data and node.left != None:
return self.findNode(node.left,value) # Added return
elif value > node.data and node.right != None:
return self.findNode(node.right,value) # Added return
else:
return None
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 ()