4
\$\begingroup\$

I wrote a min-heap using a binary tree. How can I improve the time complexity of insert and delete function to be \$\mathcal{O}(log(n))\$?

'''
Min Heap Tree Implementation
'''
class Node:
 def __init__(self, data):
 self.data = data
 self.left = None
 self.right = None
class HeapBT:
 def __init__(self):
 self.head = None
 def insert(self, data):
 if self.head is None:
 self.head = Node(data)
 return
 lst = []
 lst.append(self.head)
 while lst:
 currentNode = lst.pop(0)
 if currentNode.left is None:
 currentNode.left = Node(data)
 break
 if currentNode.right is None:
 currentNode.right = Node(data)
 break
 if currentNode.left is not None:
 lst.append(currentNode.left)
 if currentNode.right is not None:
 lst.append(currentNode.right)
 self.heapifyBottomUp(data)
 def bfs(self):
 if self.head is None:
 return
 lst = []
 lst.append(self.head)
 while lst:
 currentNode = lst.pop(0)
 print(currentNode.data)
 if currentNode.left is not None:
 lst.append(currentNode.left)
 if currentNode.right is not None:
 lst.append(currentNode.right)
 def heapifyBottomUp(self, data):
 count = 1
 while count:
 count = 0
 lst = []
 lst.append(self.head)
 while lst:
 currentNode = lst.pop(0)
 if currentNode.left is not None:
 if currentNode.left.data == data:
 if currentNode.data > currentNode.left.data:
 count = 1
 temp = currentNode.data
 currentNode.data = currentNode.left.data
 currentNode.left.data = temp
 break
 elif currentNode.left != data:
 lst.append(currentNode.left)
 if currentNode.right is not None:
 if currentNode.right.data == data:
 if currentNode.data > currentNode.right.data:
 count = 1
 temp = currentNode.data
 currentNode.data = currentNode.right.data
 currentNode.right.data = temp
 break
 elif currentNode.right != data:
 lst.append(currentNode.right)
 def heapifyTopDown(self, node):
 if node is None:
 return
 if node.left is not None and node.right is not None:
 if node.left.data < node.data and node.right.data < node.data:
 if node.left.data < node.right.data:
 temp = node.data
 node.data = node.left.data
 node.left.data = temp
 self.heapifyTopDown(node.left)
 return
 else:
 temp = node.data
 node.data = node.right.data
 node.right.data = temp
 self.heapifyTopDown(node.right)
 return
 elif node.left.data < node.data and node.right.data > node.data:
 temp = node.left.data
 node.left.data = node.data
 node.data = temp
 self.heapifyTopDown(node.left)
 return
 else:
 temp = node.right.data
 node.right.data = node.data
 node.data = temp
 self.heapifyTopDown(node.right)
 return
 elif node.left is not None:
 if node.left.data < node.data:
 temp = node.data
 node.data = node.left.data
 node.left.data = temp
 self.heapifyTopDown(node.left)
 return
 elif node.right is not None:
 if node.right.data < node.data:
 temp = node.data
 node.data = node.right.data
 node.right.data = node.data
 self.heapifyTopDown(node.right)
 return
 def pop(self):
 if self.head is None:
 return 'Heap is empty.'
 data = self.head.data
 if self.head.left is None and self.head.right is None:
 self.head = None
 return data
 lst = []
 lst.append(self.head)
 while lst:
 currentNode = lst.pop(0)
 if currentNode.left is not None:
 lst.append(currentNode.left)
 if currentNode.right is not None:
 lst.append(currentNode.right)
 leafData = currentNode.data
 lst = []
 lst.append(self.head)
 while lst:
 currentNode = lst.pop(0)
 if currentNode.left is not None:
 if currentNode.left.data == leafData:
 currentNode.left = None
 break
 else:
 lst.append(currentNode.left)
 if currentNode.right is not None:
 if currentNode.right.data == leafData:
 currentNode.right = None
 break
 else:
 lst.append(currentNode.right)
 self.head.data = leafData
 self.heapifyTopDown(self.head)
 return data
 def peek(self):
 if self.head is None:
 return 'self.head is None'
 return self.head.data
avl = HeapBT()
avl.insert(11)
avl.insert(10)
avl.insert(9)
avl.insert(8)
avl.insert(7)
avl.insert(6)
avl.insert(5)
avl.insert(4)
avl.insert(3)
avl.insert(2)
avl.insert(1)
avl.insert(-1)
avl.insert(43)
avl.insert(34)
avl.insert(53)
avl.insert(-1123)
avl.insert(-100)
avl.insert(-11233)
#avl.bfs()
print
print
print(avl.pop())
print(avl.pop())
print(avl.pop())
print(avl.pop())
print(avl.pop())
print(avl.pop())
print(avl.pop())
print(avl.pop())
print(avl.pop())
print(avl.pop())
print(avl.pop())
print(avl.pop())
print(avl.pop())
print(avl.peek(),'peek')
print
avl.bfs()
AlexV
7,3532 gold badges24 silver badges47 bronze badges
asked Oct 17, 2019 at 9:37
\$\endgroup\$
1
  • 2
    \$\begingroup\$ Is there a reason why you implement binary heap using a binary tree? It is much simpler to use a list to implement binary heap, with log performance on insert and delete. \$\endgroup\$ Commented Oct 17, 2019 at 14:48

1 Answer 1

1
\$\begingroup\$

To achieve the \$\mathcal{O}(log(n))\$ time complexity of insert and delete functions you should store the binary tree as an array - Heap implementation. Because you need to have a link to the last element for performing insert and delete operations and the easiest (common) way to track this link is an array representation of the binary tree. You can devise your own method of tracking the last element for your binary tree representation, but I think it will be similar to the array method at the end.

My implementation:

class BinHeap:
 def __init__(self):
 self.lst = []
 def insert(self, data):
 self.lst.append(data)
 self.heapify_up(len(self.lst) - 1)
 def pop_root(self):
 root = self.lst[0]
 last = self.lst.pop()
 if len(self.lst) > 0:
 self.lst[0] = last 
 self.heapify_down(0, 0)
 return root
 def heapify_down(self, parent_idx, child_idx):
 if child_idx >= len(self.lst):
 return
 parent_greater_bool = self.lst[parent_idx] > self.lst[child_idx]
 if parent_greater_bool:
 self.lst[parent_idx], self.lst[child_idx] = self.lst[child_idx], self.lst[parent_idx]
 if parent_greater_bool or parent_idx == 0:
 self.heapify_down(child_idx, child_idx * 2 + 1)
 self.heapify_down(child_idx, child_idx * 2 + 2)
 def heapify_up(self, child_idx):
 parent_idx = (child_idx - 1) // 2
 if parent_idx < 0:
 return
 if self.lst[parent_idx] > self.lst[child_idx]: 
 self.lst[parent_idx], self.lst[child_idx] = self.lst[child_idx], self.lst[parent_idx]
 self.heapify_up(parent_idx)

Testing:

heap = BinHeap()
heap.insert(4)
heap.insert(5)
print(heap.lst)
print(heap.pop_root())
print(heap.pop_root())
print(heap.lst)
###Output:
# [4, 5]
# 4
# 5
# []
heap.insert(4)
heap.insert(5)
heap.insert(3)
heap.insert(7)
heap.insert(9)
heap.insert(10)
heap.insert(2)
print(heap.lst)
print(heap.pop_root())
print(heap.lst)
heap.insert(1)
print(heap.lst)
###Output:
# [2, 5, 3, 7, 9, 10, 4]
# 2
# [3, 5, 4, 7, 9, 10]
# [1, 5, 3, 7, 9, 10, 4]
answered Oct 19, 2019 at 13:13
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.