I created a function that inserts a node to its correct position.
For example:
root = converts_list_to_linked_list([4, 7, 9, 14]) #I have a linked list: 4->7->9->14
The Function:
insert_ordered(root, 12)
returns a linked list of "4->7->9->12->14->None"
class LN:
def __init__(self, value):
self.value = value
self.next = None
def insert_ordered(root, data):
node = LN(data)
if root == None:
return node
else:
if root.value > data:
node.next = root
return node
else:
temp, prev = root, None
while temp.next and temp.value <= data:
prev = temp
temp = temp.next
if temp.next == None and temp.value <= data:
temp.next = node
else:
node.next = prev.next
prev.next = node
return root
Is there any way to solve this problem recursively? I can't grasp the idea on how too.
Try this:
class LN:
def __init__(self, value, node=None):
self.value = value
self.next = node
def insert_ordered(root, data):
if root == None or root.value > data:
return LN(data, root)
root.next = insert_ordered(root.next, data)
return root
If you want to insert in descending order change root.value > data to root.value < data
The following uses an auxiliary function to recursively insert into the list:
class LN:
def __init__(self, value):
self.value = value
self.next = None
def insert_ordered(self, data):
node = LN(data)
return self.insert_ordered_aux(node)
def insert_ordered_aux(self,node):
if self.value >= node.value: # add node before current node
node.next = self
return node
elif self.next: # do the recursion
self.next = self.next.insert_ordered_aux(node)
return self
else: # add node at end of list
self.next = node
return self
#test:
root = LN(4)
root = root.insert_ordered(9)
root = root.insert_ordered(14)
root = root.insert_ordered(6)
root = root.insert_ordered(-2)
root = root.insert_ordered(12)
def print_list(node):
if (node):
print(node.value)
print_list(node.next)
print_list(root)
How are you using it, and is your pasted code's indentation correct?
After some indentation adjustments, this is how i use it, and what i get:
class LN:
def __init__(self, value):
self.value = value
self.next = None
def insert_ordered(root, data):
node = LN(data)
if root == None:
return node
else:
if root.value > data:
node.next = root
return node
else:
temp, prev = root, None
while temp.next and temp.value <= data:
prev = temp
temp = temp.next
if temp.next == None and temp.value <= data:
temp.next = node
else:
node.next = prev.next
prev.next = node
return root
#Use:
a1 = LN(1)
a1.next = a2 = LN(5)
a2.next = a3 = LN(10)
a3.next = a4 = LN(15)
root = a1
#Insert tests
root = root.insert_ordered(13)
root = root.insert_ordered(12)
root = root.insert_ordered(15)
root = root.insert_ordered(-5)
root = root.insert_ordered(17)
t = root
while(t):
print(str(t.value) + " ")
t = t.next
Output:
-5
1
5
10
12
13
15
15
17
Related
i wonder how to make insertion method without recursion.
I made it, but there's something wrong. AttributeError: 'NoneType' object has no attribute 'item' occured.
I know what this error means, but I can't understand why this happend. parent is not None... it moves to curr so it can have item... why this happens?
this is my code.
class BSTNode:
def __init__(self, item, left = None, right = None):
self.item = item
self.left = left
self.right = right
class BSTree():
def __init__(self):
self.root = None
def insert(self, data):
parent = None
curr = self.root
while curr is not None:
if data < curr.item:
parent = curr
curr = curr.left
elif data > curr.item:
parent = curr
curr = curr.right
else:
return False
if curr is None:
if parent is None:
newNode = BSTNode(data)
self.root = newNode
if data < parent.item:
newNode = BSTNode(data)
curr = newNode
return True
elif data > parent.item:
newNode = BSTNode(data)
curr = newNode
return True
def search(self, data):
curr = self.root
while curr is not None:
if data < curr.item:
curr = curr.left
elif data > curr.item:
curr = curr.right
else:
return True
return False
def delete(self, data):
parent = None
curr = self.root
while curr is not None:
if data < curr.item:
parent = curr
curr = curr.left
elif data > curr.item:
parent = curr
curr = curr.right
else:
break
if curr is None:
return False
if curr.left is None:
if parent is None:
self.root = curr.right
else:
if data < parent.item:
parent.left = curr.right
else:
parent.right = curr.right
elif curr.right is None:
if parent is None:
self.root = curr.left
else:
if data < parent.item:
parent.left = curr.left
else:
parent.right = curr.left
else:
parentMaxNode = curr
maxNode = curr.left
while maxNode.right is not None:
parentMaxNode = maxNode
maxNode = maxNode.right
curr.item = maxNode.item
if parentMaxNode.right is maxNode:
parentMaxNode.right = maxNode.left
else:
parentMaxNode.left = maxNode.left
return True
I think you have the problem with insert method and i think my code below is work for you
class BSTNode:
def __init__(self, item, left = None, right = None):
self.item = item
self.left = left
self.right = right
class BSTree():
def __init__(self):
self.root = None
def insert(self, item):
# if the tree is empty, the new item becomes the root node
if self.root is None:
self.root = BSTNode(item)
else:
# find the parent node of the new item
parent = self.root
while True:
if item < parent.item:
# if the item is less than the parent node,
# insert the item to the left of the parent node
if parent.left is None:
parent.left = BSTNode(item)
break
else:
parent = parent.left
else:
# if the item is greater than or equal to the parent node,
# insert the item to the right of the parent node
if parent.right is None:
parent.right = BSTNode(item)
break
else:
parent = parent.right
The problem is with this part at the end of the insert function:
if data < parent.item:
newNode = BSTNode(data)
curr = newNode
return True
elif data > parent.item:
newNode = BSTNode(data)
curr = newNode
return True
The statement curr = newNode just assigns a node reference to a variable. Assigning to a variable can never mutate an object (like a node or a list). If you need to mutate a list (like attaching a left or right child to a node), you really need to assign to an attribute of an existing node (the parent).
So that part of the code must be replaced with this:
if data < parent.item:
newNode = BSTNode(data)
parent.left = newNode
return True
elif data > parent.item:
newNode = BSTNode(data)
parent.right = newNode
return True
...which can be shortened to:
newNode = BSTNode(data)
if data < parent.item:
parent.left = newNode
elif data > parent.item:
parent.right = newNode
return True
(Note that at that point it is already guaranteed that data != parent.item)
I'm creating a function that takes in a sorted linked list and a value. I create a new node with the given value by new_node = LN(v). I am trying to return a linked list with the new node in the correct position. The example will help clarify.
Ex)
ll = converts_list_to_linked_list([4, 7, 9, 14]) #I have a linked list: 4->7->9->12->14
The Function:
insert_ordered(ll, 12)
returns a linked list of "4->7->9->12->14->None"
I am completely stuck on how to insert the new node in the correct position. The last else statement in my function is incorrect.
def insert_ordered(ll,x):
new_node = LN(v) #Creates new node
#If given ll is empty, newnode is the linkedlist
if ll == None:
ll = new_node
#Makes new_node the head of ll if first val is >= new_node value.
elif ll.value >= new_node.value:
temp = ll
ll = new_node
ll.next = temp
#[ERROR] Adds new_node between two nodes of ll in sorted order.
else:
while ll.next != None:
if ll.value < new_node.value:
ll = ll.next
new_node.next = ll.next
ll.next = new_node
return ll
After solving this iteratively, is it possible to solve it recursively?
Try this:
class LN:
def __init__(self, value):
self.value = value
self.next = None
def insert_ordered(root, data):
node = LN(data)
if root == None:
return node
else:
if root.value > data:
node.next = root
return node
else:
temp, prev = root, None
while temp.next and temp.value <= data:
prev = temp
temp = temp.next
if temp.next == None and temp.value <= data:
temp.next = node
else:
node.next = prev.next
prev.next = node
return root
root = None
root = insert_ordered(root, 4)
root = insert_ordered(root, 7)
root = insert_ordered(root, 9)
root = insert_ordered(root, 14)
root = insert_ordered(root, 12)
#4->7->9->12->14
I have problem with infinite loop in getMinimal() method. It works in this way :
1)Take node,
2)If node has other node on the left - go to other one.
3)Repeat as far as node has sth on the left side
4)Return the minimal node.
But sometimes it works in infinite loop for example from 1000 to 400, then to 4 then..to 1000! I have no ide where I make mistake. I reviewed this code many times,every single "pointer" to parent/left/right node is okay! Please - help.
Algorithm works okay to "handwritten" trees - ~20nodes. I wanted to test it in better cases - 2500nodes,generated by random lib (from -10k to 10k).
import random
class Node:
def __init__(self, val):
self.val = val
self.parent = None
self.right = None
self.left = None
# Class of node.
def str(self):
return str(self.val)
class MyTree:
def __init__(self, node):
self.root = node
def insert(self, node):
current = self.root
a = True
while a:
if node.val > current.val:
if current.right is not None:
current = current.right
continue
else:
current.right = node
node.parent = current
a = False
if node.val <= current.val:
if current.left is not None:
current = current.left
continue
else:
current.left = node
node.parent = current
a = False
def search(self, node):
current = self.root
while node.val != current.val:
if node.val > current.val:
current = current.right
continue
elif node.val <= current.val:
current = current.left
continue
if node.val == current.val:
return current
else:
print("There is no such node!")
def delete(self, node):
if isinstance(node, (float, int)):
node = self.search(node)
if node is self.root:
self.__deleteRoot()
return
else:
if node.right is None and node.left is None:
self.__deleteNN(node)
return
if node.right is None and node.left is not None:
self.__deleteLN(node)
return
if node.right is not None and node.left is None:
self.__deleteNR(node)
return
if node.right is not None and node.left is not None:
self.__deleteLR(node)
return
def __deleteNN(self, node):
if node.parent.left is node:
node.parent.left = None
if node.parent.right is node:
node.parent.right = None
def __deleteLN(self, node):
parent = node.parent
son = node.left
# parent replaced
if parent.left is node:
parent.left = son
if parent.right is node:
parent.right = son
son.parent = parent
def __deleteNR(self,node):
parent = node.parent
son = node.right
# replace parent
if parent.left is node:
parent.left = son
if parent.right is node:
parent.right = son
son.parent = parent
def __deleteLR(self, node):
minimal = self.getMinimal(node.right)
if minimal.parent.left is minimal:
minimal.parent.left = None
if minimal.parent.right is minimal:
minimal.parent.right = None
# parent of minimal done..
if node.parent.left is node:
node.parent.left = minimal
if node.parent.right is node:
node.parent.right = minimal
minimal.right = node.right
minimal.left = node.left
def getMinimal(self, node):
k = node
while k.left is not None:
k = k.left
return k
def getMax(self):
current = self.root
while current.right:
current = current.right
return current
def __trav(self, node):
if not node:
return
print(node.val)
self.__trav(node.left)
self.__trav(node.right)
def printTrav(self):
self.__trav(self.root)
def __deleteRoot(self):
if self.root.left is None and self.root.right is None:
self.root = None
return
if self.root.left is None and self.root.right is not None:
# left empty,right full
self.root.right.parent = None
self.root = self.root.right
return
if self.root.left is not None and self.root.right is None:
# right empty, left full
self.root.left.parent = None
self.root = self.root.left
return
# node has both children
if self.root.left is not None and self.root.right is not None:
temp = self.getMinimal(self.root.right) # minimal from right subtree
# sometimes it could be like this..
# r
# \
# x
if temp.parent.left is temp:
temp.parent.left = None
else:
temp.parent.right = None
self.root.left.parent = temp
self.root.right.parent = temp
temp.right = self.root.right
temp.left = self.root.left
self.root = temp
self.root.parent = None
return
def search(self, val):
node = self.root
if node.val == val:
return node
if val > node.val and node.right is not None:
node = node.right
if val < node.val and node.left is not None:
node = node.left
else:
print("There's no such value!")
return
def printMax(self):
print(self.getMax().val)
def printMin(self):
print(self.getMinimal(self.root).val)
arr=[None]*2500
for x in range(2500):
arr[x]=Node(random.randint(-10000,10000))
myTree = MyTree(arr[0])
for x in range(1,2500):
myTree.insert(arr[x])
for x in range(2500):
myTree.delete(arr[x])
It is suspicious that you define search twice.
Still that said, here is how I would debug this. I would modify your program to read from a file, try to run, and then detect an endless loop and bail out. Now write random files until you have one that causes you to crash.
Once you have a random file that shows the bug, the next step is to make it minimal. Here is a harness that can let you do that.
import itertools
flatten = itertools.chain.from_iterable
# bug_found should be a function that takes a list of elements and runs your test.
# example should be an array that demonstrates the bug.
def find_minimal (bug_found, example):
parts = [example]
while 1 < max(len(part) for part in parts):
i = 0
while i < len(parts):
if 1 == len(parts[i]):
i = i + 1
else:
part = parts.pop(i)
# Divide in 2.
mid = len(part)/2
part1 = part[0:mid]
part2 = part[mid:len(part)]
# Do we need part1?
parts.insert(i, part1)
if bug_found(flatten(parts)):
i = i + 1
parts.insert(i, part2)
else:
parts[i] = part2
# Do we need part2?
if bug_found_func(flatten(parts)):
i = i + 1
else:
parts.pop(i)
return list(flatten(parts))
Just let it run, and after some time it is likely to find a small example. Which will greatly aid in debugging.
So - I found 2 serious bugs in code. Both in LR ("standard" node and root). As I suspected - bugs were in pointers. Now tree is working (tested few times for 20k,30k and 100k nodes). Solved.
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('')
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 ()