Data Structures Heaps
Heaps are a type of binary tree where each parent node is either less than or equal to (in a min heap) its children. Unlike binary search trees, heaps are not sorted but do follow this specific property to efficiently support priority queue operations.
Heaps primarily support two key operations: inserting a new element and removing the top element. These operations are designed to maintain the heap property, ensuring that the heap is correctly updated and balanced:
Operations | Time | Space |
---|---|---|
Push | O(log n) | O(1) |
Pop | O(log n) | O(1) |
Peek | O(1) | O(1) |
Heapify | O(n) | O(1) |
Delete | O(log n) | O(1) |
The structure property of heaps ensures that they are always complete binary trees. This means all levels of the tree are fully filled except maybe the last level, which is filled from left to right.
This structural property not only ensures a balanced distribution of nodes but also guarantees an optimal height, allowing for efficient operations. The completeness of the heap also optimizes storage by eliminating the need for pointers typically required in trees, allowing heaps to be efficiently implemented using arrays.
The heap property states that each parent node's value is less than or equal to the values of its children (in a min heap). While heaps do not store elements in a strictly sorted order, the heap property ensures that the path from any node to the root node will always be sorted. This property allows for efficient access to the heap's maximum or minimum element.
The heapify function is a fundamental operation for converting any array into a heap structure. This process rearranges the elements of the array to satisfy the heap property, ensuring that for every node the value of the node is not less than the value of its parent, forming a min heap.
Starting from the last non-leaf node all the way up to the root node, the process applies the sift-down
operation. This ensures that each subtree satisfies the heap property before finally transforming the entire array into a heap:
The siftDown
method is important in the heapify
process. It compares the parent node with its children to ensure the heap property is maintained, swapping the nodes when necessary. This function continues until the subtree rooted at the node being sifted down satisfies the heap property.
Heaps come in two primary forms: min heaps, where the parent node is less than or equal to its children, and max heaps, where the parent node is greater than or equal to its children. Min heaps are for accessing the the smallest element, such as scheduling tasks based on their priority level where the lowest value indicates the highest priority. Max heaps are for accessing the largest element.
When you are maintaining a collection of the k
elements, using heaps will help you keep track of the smallest or largest k
elements. A min heap keeps track of the k
largest elements by ensuring that the smallest of these k
elements is always at the root. A max heap is used to maintain thek
smallest elements:
In Python, heaps are implemented as a min heap. This is a problem when a max heap is required. To create a max heap in Python, a common workaround involves negating the values before adding them to the heap. By negating each value, the heap's property is inverted: the largest elements (when negative are now the smallest) bubble up to the root of the heap. When accessing these elements, their values are negated again to restore their original value.
Heaps efficiently organize data for priority-based access, with min heaps accessing the smallest element and max heaps the largest. Now let's implement a min heap using what we learned. Key operations include heapify, inserting elements, and extracting the highest (or lowest) priority item:
Heaps should be your go-to data structure for keeping track of k
smallest (or largest) elements, and supporting operations like finding the minimum or maximum element efficiently. Here are some tips and tricks for using heaps effectively in coding interviews: