DSA-Module 3Notes
DSA-Module 3Notes
Module 3
Heaps
Heap
A Heap is a complete binary tree that follows the heap-order property,
meaning:
Max-Heap: The parent node is always greater than or equal to its
children.
Min-Heap: The parent node is always smaller than or equal to its
children.
Properties of Heap:
1. Complete Binary Tree: All levels are completely filled except possibly
the last.
2. Heap-Order Property: The value of each parent node is either greater
(Max-Heap) or smaller (Min-Heap) than its children.
Applications: Used in priority queues, Dijkstra’s algorithm, and heapsort.
Page 1 of 70
2. Heaps
A Heap is a specialized binary tree that follows the heap-order property:
Max-Heap: The parent node is always greater than or equal to its
children.
Min-Heap: The parent node is always smaller than or equal to its
children.
It supports efficient priority queue operations, with O (1) access to the root and
O (log n) insertions/deletions.
3. Balanced Search Trees vs. Heaps
Feature Balanced Search Tree Heap
Structure Binary Search Tree with Complete Binary Tree
balance constraints
Order Property In-order traversal gives No strict order, only
sorted elements heap property
Search Complexity O (log n) O (n) in the worst case
Insert/Delete O (log n) O (log n)
Complexity
Application Database indexing, Priority Queues,
efficient searching Scheduling
Page 2 of 70
heap_t *create_heap(void)
{
heap_t *hp;
hp = (heap_t *) malloc( sizeof(heap_t) );
hp->tree = create_tree();
return( hp );
}
int heap_empty(heap_t *hp)
{
return( hp->tree->left == NULL );
}
heap_el_t find_min(heap_t *hp)
{
return( hp->current_min );
}
void insert_heap( key_t new_key, object_t *new_obj, heap_t *hp)
{
If (hp->tree->left == NULL || new_key < hp->current_min.key )
{
Page 3 of 70
hp->current_min.key = new_key;
hp->current_min.object = new_obj;
}
insert(hp->tree, new_key, new_obj );
}
object_t *delete_min(heap_t *hp)
{
object_t *del_obj;
tree_node_t *tmp_node;
if (hp->tree->left == NULL)
return (NULL); /* heap empty */
else
{
del_obj = hp->current_min.object;
delete(hp->tree, hp->current_min.key );
tmp_node = hp->tree;
if( tmp_node->left != NULL )
/* update current_min */
{
while( tmp_node->right != NULL )
tmp_node = tmp_node->left;
hp->current_min.key = tmp_node->key;
hp->current_min.object = (object_t *)
tmp_node->left;
}
return( del_obj );
}
Page 4 of 70
}
void remove_heap(heap_t *hp)
{
remove_tree( hp->tree );
free( hp );
}
Theorem. The heap structure can be realized using any balanced search tree
with time O (log n) for insert and delete min and O (1) for find min
operations.
The heap operations are implemented as follows:
{find min: return current min->key and current min->object.
{insert:
1. Split the search tree at current min->key, and add the lower tree to
the invalid nodes structure.
2. Insert the new key in search tree.
3. If the new key is below current min->key, set current min to
the new key and object.
{delete min:
1. Delete the object current min->object.
2. Move current min to the next list position.
3. If current min->key is now larger than the key in the root of the
balanced search tree, add the left subtree of the balanced search tree to
the invalid nodes structure; take the right subtree as new search tree; and
return the node of the old root to the free list.
4 Return several nodes from the invalid nodes structure to the free list.
Page 5 of 70
Theorem. The heap structure can be realized using a balanced search tree
with lazy deletion in time O (log n) for insert and O (1) for find min and
delete min operations if the heap contains n elements.
Array-Based Heaps
A heap is a specialized tree-based data structure that satisfies the heap
property. It is commonly implemented using an array due to its efficient
memory usage and fast access times.
Heap Property
A heap can be of two types:
1. Max Heap – The key at the parent node is always greater than or equal to
the keys of its children.
2. Min Heap – The key at the parent node is always less than or equal to the
keys of its children.
Array Representation of a Heap
Since a heap is a complete binary tree, it can be stored in an array without
using pointers. The array representation is based on level-order traversal of the
tree. Given a big array heap key [MAX SIZE], a correct heap satisfies the
following conditions:
1. The entries used by the heap are a beginning interval of the array; if the
heap currently contains n elements, it uses the array positions 0 to n − 1.
2. For all i ≥ 0 have
heap key[i] < heap key [2i + 1] if 2i + 1 < n and
heap key[i] < heap key [2i + 2] if 2i + 2 < n.
The root is stored at index 0
For a node at index i:
o Left child is at index 2i + 1
o Right child is at index 2i + 2
o Parent is at index ⌊i/2⌋
Page 6 of 70
Example:
For the following max heap:
50
/ \
30 40
/ \ / \
10 20 35 38
The array representation is:
[50, 30, 40, 10, 20, 35, 38] (1-based indexing)
Heap Operations
1. Insertion in Heap
o Insert the new element at the end of the array.
o Perform heapify-up (percolate up) to restore the heap property.
o Time Complexity: O(log n)
Page 7 of 70
Page 8 of 70
Applications
Priority Queues
Heap Sort
Graph Algorithms (Dijkstra’s and Prim’s Algorithm)
Scheduling and Load Balancing
Implementation of this standard array-based heap structure, with a given
maximum size. Each element of the heap consists of a key and a pointer to an
object, and this is what we return with the query:
typedef struct {key_t key; object_t *object;}heap_el_t;
typedef struct { int max_size;
int current_size;
heap_el_t *heap; } heap_t;
heap_t *create_heap(int size)
{
heap_t *hp;
hp = (heap_t *) malloc( sizeof(heap_t) );
hp->heap = (heap_el_t *)
malloc( size * sizeof(heap_el_t) );
hp->max_size = size;
hp->current_size = 0;
return( hp );
}
int heap_empty(heap_t *hp)
{
return( hp->current_size == 0 );
}
heap_el_t *find_min(heap_t *hp)
{
Page 9 of 70
return( hp->heap );
}
int insert( key_t new_key, object_t *new_object, heap_t *hp)
{
if ( hp->current_size < hp->max_size )
{
int gap;
gap = hp->current_size++;
while(gap > 0 && new_key < (hp->heap[(gap-1)/2]).key )
{
(hp->heap[gap]).key = (hp->heap[(gap-1)/2]).key;
(hp->heap[gap]).object = (hp->heap[(gap-1)/2]).object;
gap = (gap-1)/2;
}
(hp->heap[gap]).key = new_key;
(hp->heap[gap]).object = new_object;
return( 0 ); /* insert successful */
}
else
return( -1 ); /* Heap overflow */
}
Page 10 of 70
if( hp->current_size == 0 )
return( NULL );
/*failed: delete from empty heap */
del_obj = (hp->heap[0]).object;
gap = 0;
while( ! reached_top )
{
if( 2*gap + 2 < hp->current_size )
{
if( (hp->heap[2*gap+1]).key < (hp->heap[2*gap+2]).key)
newgap = 2*gap + 1;
else
newgap = 2*gap + 2;
(hp->heap[gap]).key =
(hp->heap[newgap]).key;
(hp->heap[gap]).object = (hp->heap[newgap]).object;
gap = newgap;
}
else if ( 2*gap + 2 == hp->current_size )
{
newgap = 2*gap + 1;
(hp->heap[gap]).key = (hp->heap[newgap]).key;
(hp->heap[gap]).object = (hp->heap[newgap]).object;
hp->current_size -= 1;
return(del_obj);
/* finished, came out exactly on last element */
}
Page 11 of 70
else
reached_top = 1;
}
/* propagated gap to the top, now move gap down again to insert last
object in the right place */
last = --hp->current_size;
while(gap > 0 && (hp->heap[last]).key < (hp->heap[(gap-1)/2]).key )
{
(hp->heap[gap]).key = (hp->heap[(gap-1)/2]).key;
(hp->heap[gap]).object = (hp->heap[(gap-1)/2]).object;
gap = (gap-1)/2;
}
(hp->heap[gap]).key = (hp->heap[last]).key;
(hp->heap[gap]).object =(hp->heap[last]).object;
/* filled gap by moving last element in it*/
return( del_obj );
}
void remove_heap(heap_t *hp)
{
free( hp->heap );
free( hp );
}
Theorem. The heap structure of fixed maximum size can be realized using an
array in time O (1) for find min and O (log n) for insert and delete min
operations.
Page 12 of 70
1. Heap-Ordered Trees
A heap-ordered tree is a binary tree that satisfies the heap property. The
heap property ensures that:
Max-Heap Property: The value of each node is greater than or equal
to the values of its children.
o Mathematically, for every node N,
N ≥ left child and N ≥ right
Min-Heap Property: The value of each node is less than or equal to the
values of its children.
o Mathematically, for every node N,
N ≤ left child and N ≤ right child
Additionally, a heap is always a complete binary tree, meaning all levels are
completely filled except possibly the last level, which is filled from left to right.
Example of Max-Heap:
50
/ \
30 40
/ \ /
10 20 35
Here, each parent node is greater than its children.
Example of Min-Heap:
10
/ \
20 30
Page 13 of 70
/ \ /
40 50 35
Here, each parent node is smaller than its children.
Applications of Heap-Ordered Trees:
Priority Queues (Efficient retrieval of maximum/minimum element)
Heap Sort (Sorting algorithm based on heap property)
Graph Algorithms (Dijkstra’s shortest path, Prim’s algorithm)
The structure of a node of a (binary) heap-ordered tree is as follows:
typedef struct hp_n_t {
key_t key;
object_t *object;
struct hp_n_t *left;
struct hp_n_t *right;
/* possibly additional information */
} heap_node_t;
We named the two pointers again left and right, but different from the search
tree, there is no order relation between them. Again, we define a heap ordered
tree recursively: the heap-ordered tree is either empty or contains in the root
node a key, an object, and two pointers, each of which might be either NULL or
point to another heap-ordered tree in which all keys are larger than the key in
the root node. Any structure with these properties is a heap-ordered tree for its
objects and key values.
Page 14 of 70
Page 15 of 70
2. Half-Ordered Trees
A half-ordered tree is a binary tree where only one of the subtrees (left or
right) satisfies the heap property instead of both. This means:
The left or right subtree maintains either min-heap or max-heap order,
but the entire tree does not strictly follow it.
Unlike a full heap, a half-ordered tree may not be completely balanced
or complete.
Example of Half-Ordered Tree (Max-Half-Heap):
70
/ \
60 30
/ \
40 50
Here, the left subtree follows the max-heap property, but the right subtree
does not.
Applications of Half-Ordered Trees:
Used in specialized priority queue implementations
Intermediate step in heap construction
Optimization for search operations in certain tree-based algorithms
Page 16 of 70
Leftist Heaps
A Leftist Heap is a type of priority queue implemented as a binary tree that
satisfies two properties:
1. Heap Property (Min-Heap or Max-Heap)
2. Leftist Property (Ensures tree is skewed to the left)
1. Heap Property
A leftist heap follows the heap order property, meaning:
In a Min-Heap, the value at each node is less than or equal to the values
of its children.
In a Max-Heap, the value at each node is greater than or equal to the
values of its children.
2. Leftist Property
The leftist property ensures that the left subtree is always deeper than the
right subtree. This is measured using the null path length (NPL), which is the
shortest path to a NULL (or leaf) node.
For any node N, NPL(left child) ≥ NPL(right child)
The null path length (NPL) of a node is defined as:
o NPL(NULL) = −1
o NPL(Leaf node) = 0
o NPL(N)=1+min (NPL(left child),NPL(right child))
This ensures that the tree is skewed towards the left, making operations
efficient.
Page 17 of 70
20 30
/ \
40 50
Heap property: 10 < 20, 10 < 30, etc.
Leftist property: Left subtree is deeper than the right subtree
4. Operations on Leftist Heaps
The key operation in leftist heaps is merging two heaps, which is done using a
recursive merge algorithm.
a) Merge Operation
Compare the roots of two heaps.
The smaller root becomes the root of the merged heap.
Recursively merge the right subtree of the smaller root with the other
heap.
Swap children if necessary to maintain the leftist property.
✅ Time Complexity: O(log n) (since the right subtree is always shorter)
Page 18 of 70
Page 19 of 70
{
tmp1->right = tmp2;
push( tmp1 );
tmp1 = tmp2;
tmp2 = tmp2->right;
}
else
{
tmp1->right = tmp3;
push( tmp1 );
tmp1 = tmp3;
tmp3 = tmp3->right;
}
}
if( tmp2 == NULL)
tmp1->right = tmp3;
else
tmp1->right = tmp2;
/* merging of right paths complete, now recompute rank and restore
leftist property */
push( tmp1 );
while( !stack_empty() )
{
tmp1 = pop();
Page 20 of 70
{
tmp2 = tmp1->left;
tmp1->left = tmp1->right;
tmp1->right = tmp2;
}
if( tmp1->right == NULL )
tmp1->rank = 1;
else
tmp1->rank = tmp1->right->rank +1;
}
remove_stack();
return( root );
}
b) Insertion
1. Create a new node as a single-element heap.
2. Merge it with the existing heap. ✅ Time Complexity: O(log n)
Page 21 of 70
object_t *object;
struct hp_n_t *left;
struct hp_n_t *right;
} heap_node_t;
heap_node_t *create_heap(void)
{
heap_node_t *tmp_node;
tmp_node = get_node();
tmp_node->rank = 0;
return ( tmp_node );
}
int heap_empty(heap_node_t *hp)
{
return ( hp->rank == 0 );
}
key_t find_min_key(heap_node_t *hp)
{
return ( hp->key );
}
object_t *find_min_object(heap_node_t *hp)
{
return( hp->object );
}
void remove_heap(heap_node_t *hp)
{
heap_node_t *current_node, *tmp;
if( hp->rank == 0)
Page 22 of 70
return_node( hp );
else
{
current_node = hp;
while(current_node != NULL )
{
if( current_node->left == NULL )
{
tmp = current_node->right;
return_node( current_node );
current_node = tmp;
}
else
{
tmp = current_node;
current_node = current_node->left;
tmp->left = current_node->right;
current_node->right = tmp;
}
}
}
}
Page 23 of 70
hp->object = new_obj;
hp->key = new_key;
hp->left = hp->right = NULL;
hp->rank = 1;
}
else if( new_key < hp->key )
/* new minimum, replace root */
{
heap_node_t *tmp;
tmp = get_node();
tmp->left = hp->left;
tmp->right = hp->right;
tmp->key = hp->key;
tmp->rank = hp->rank;
tmp->object = hp->object;
hp->left = tmp;
hp->right = NULL;
hp->key = new_key;
hp->object = new_obj;
hp->rank = 1;
}
else /* normal insert */
{
heap_node_t *tmp, *tmp2, *new_node;
tmp = hp;
create_stack();
/* go down right path to the insertion point */
Page 24 of 70
Page 25 of 70
tmp = pop();
{
if(tmp->left->rank < tmp->right->rank )
{
tmp2 = tmp->left;
tmp->left = tmp->right;
tmp->right = tmp2;
}
tmp->rank = tmp->right->rank +1;
}
}
} /* end walking back to the root */
remove_stack();
}
return(0); /* insert always successful */
}
c) Deletion (Extract Min)
1. Remove the root node (which contains the minimum element in a Min-
Heap).
2. Merge the left and right subtrees. ✅ Time Complexity: O(log n)
object_t *delete_min(heap_node_t *hp)
{
object_t *del_obj;
heap_node_t *heap1, *heap2, *tmp;
del_obj = hp->object;
heap1 = hp->left;
heap2 = hp->right;
if( heap1 == NULL && heap2 == NULL )
Page 26 of 70
hp->rank = 0;
else
{
if ( heap2 == NULL )
tmp = heap1;
else
tmp = merge( heap1, heap2);
/* now they are merged, need to copy root to correct place */
hp->key = tmp->key;
hp->object = tmp->object;
hp->rank = tmp->rank;
hp->left = tmp->left;
hp->right = tmp->right;
return_node( tmp );
}
return( del_obj );
}
5. Applications of Leftist Heaps
Priority Queues (Faster merging than binary heaps)
Efficient merging of multiple sorted lists
Graph Algorithms (Dijkstra’s shortest path, Prim’s MST)
6. Advantages of Leftist Heaps
✅ Faster Merging: More efficient than binary heaps (O(log n) merge
complexity).
✅ Better for Dynamic Priority Queues: Useful when merging operations are
frequent.
✅ Adaptive Structure: Adjusts dynamically for optimal performance.
7. Comparison of Leftist Heap vs Binary Heap
Page 27 of 70
Page 28 of 70
object_t *object;
struct hp_n_t *left;
struct hp_n_t *right;
} heap_node_t;
1. Merge (Union) Operation
The merge operation is the fundamental operation in skew heaps. Other
operations like insertion and deletion are performed using merge.
Steps for merging two skew heaps H1 and H2:
1. If one heap is empty, return the other heap.
2. Compare the roots of both heaps.
3. Make the smaller root the new root.
4. Recursively merge the right subtree of the smaller root with the other
heap.
5. Swap the left and right children of the new root.
Time Complexity: O(log n) amortized.
heap_node_t *merge( heap_node_t *hp1,heap_node_t *hp2)
{
heap_node_t *root, *tmp1, *tmp2, *tmp3;
if( hp1->object == NULL ) /* heap 1 empty */
{
return_node( hp1 );
return( hp2 );
}
if( hp2->object == NULL ) /* heap 2 empty */
{
return_node( hp2 );
return( hp1 );
} /* select new root, setup merging */
Page 29 of 70
Page 30 of 70
}
} /* now one of the paths empty,
attach the other */
if( tmp2 == NULL)
tmp1->right = tmp3;
else
tmp1->right = tmp2;
return( root );
}
2. Insertion
To insert a new element:
1. Create a new heap with the element as the only node.
2. Merge it with the existing skew heap.
Time Complexity: O(log n) amortized.
int insert( key_t new_key, object_t *new_obj, heap_node_t *hp)
{
if(hp->object == NULL)
/* insert in empty heap */
{
hp->object = new_obj;
hp->key = new_key;
hp->left = hp->right = NULL;
}
else if( new_key < hp->key )
/* new minimum, replace root */
{
heap_node_t *tmp;
Page 31 of 70
tmp = get_node();
tmp->left = hp->left;
tmp->right = hp->right;
tmp->key = hp->key;
tmp->object = hp->object;
hp->left = tmp;
hp->right = NULL;
hp->key = new_key;
hp->object = new_obj;
}
else /* normal insert */
{
heap_node_t *current, *tmp, *new_node; current = hp;
/* go down right path to the insertion point */
while( current->right != NULL && current->right->key <
new_key)
{
tmp = current->right; /* exchange */
current->right = current->left;
current->left = tmp;
current = tmp; /* and go down */
}
/* now create new node */
new_node = get_node();
new_node->key = new_key;
new_node->object = new_obj;
/* insert new node in path, everything below goes left */
new_node->left = current->right;
Page 32 of 70
new_node->right = NULL;
current->right = new_node;
}
return(0);
}
3. Deletion of Minimum Element
To delete the minimum element (root node):
1. Remove the root.
2. Merge its left and right subtrees.
Time Complexity: O(log n) amortized.
Theorem. The skew heap structure supports the operations find min in O(1)
time and insert, merge, and delete min in amortized O(log n) time on
a heap with n elements.
Binomial Heaps
A Binomial Heap is a collection of Binomial Trees that are linked together. A
binomial tree Bk of order k is defined recursively as follows:
1. A binomial tree of order 0 is a single node.
2. A binomial tree of order k is formed by linking two binomial trees of
order k-1, making one tree the leftmost child of the other.
Properties of a Binomial Heap
1. A binomial heap is a collection of binomial trees where each tree follows
the min-heap property (i.e., the key of a parent node is smaller than or
equal to the keys of its children).
2. The heap contains at most one binomial tree of any given order kk.
3. If a binomial heap has nn nodes, it consists of at most log(n) binomial
trees, corresponding to the binary representation of n.
Structure of a Binomial Heap
A binomial heap is represented as a linked list of binomial trees arranged in
increasing order of their degree (order). Each tree follows the min-heap order
property.
Page 34 of 70
Page 35 of 70
tmp = tmp->left;
if( tmp->key < tmp_key )
tmp_key = tmp->key;
}
return( tmp_key );
}
Operations on Binomial Heaps
1. Insertion
o Create a new binomial heap with a single node.
o Merge it with the existing binomial heap.
o Time Complexity: O(log n)
Page 36 of 70
tmp->height =hp->height;
tmp2 = merge( new_node, tmp );
/* merge the heaps */
hp->left = tmp2->left;
/* merge completed, copy root back */
hp->right = tmp2->right;
hp->key = tmp2->key;
hp->object = tmp2->object;
hp->height = tmp2->height;
return_node( tmp2 );
return( 0 );
}
2. Union (Merge)
o Merge two binomial heaps by combining their binomial trees in
increasing order of degree.
o Time Complexity: O(log n)
heap_node_t *merge( heap_node_t *hp1,heap_node_t *hp2)
{
heap_node_t *tmp1, *tmp2, *current, *next;
if( hp1->height == -1 ) /* heap 1 empty */
{
return_node( hp1 );
return( hp2 );
}
if( hp2->height == -1 ) /* heap 2 empty */
{
return_node( hp2 );
return( hp1 );
Page 37 of 70
}
/* put all the blocks on the stack */
create_stack();
tmp1 = hp1; tmp2 = hp2;
while( tmp1 != NULL && tmp2 != NULL )
{
if( tmp1->height > tmp2->height )
{
push( tmp1 );
tmp1 = tmp1->left;
}
else
{
push( tmp2 );
tmp2 = tmp2->left;
}
}
/* one list is empty, push the rest of the other */
while( tmp1 != NULL )
{
push( tmp1 );
tmp1 = tmp1->left;
}
while( tmp2 != NULL )
{
push( tmp2 );
tmp2 = tmp2->left;
Page 38 of 70
}
/* now all the blocks are on the stack */
/* put them together, performing addition */
current = pop();
while( !stack_empty )
{
next = pop();
if( next->height > current->height )
{
next->left = current;
/* add in front of left list */
current = next;
}
else if( next->height == current->height )/* add blocks */
{
if( next->key < current->key )
{
next->left = current->left;
current->left = next->right;
next->right = current;
next->height += 1;
current = next;
}
else
{
next->left = current->right;
current->right = next;
Page 39 of 70
current->height +=1;
}
}
else /* next->height < current->height */
{
next->left = current->left;
/* exchange current, next*/
current->left = next;
/* insert next just below current */
}
}
return( current );
}
3. Find Minimum
o Traverse the root nodes of all binomial trees to find the minimum
key.
o Time Complexity: O(log n)
4. Extract Minimum
o Find the tree with the minimum root.
o Remove the root and create a new binomial heap with its children.
o Merge the new heap with the existing heap.
o Time Complexity: O(log n)
5. Decrease Key
o Decrease the value of a key and swap it upwards if necessary to
maintain the min-heap property.
o Time Complexity: O(log n)
6. Delete a Key
o Decrease the key to −∞ and then extract the minimum.
Page 40 of 70
Page 41 of 70
}
del_obj = min1->object;
if( min1 != min2 ) /* min1 not root, so node above exists */
{
min2->left = min1->left;
/* unlinked min1 */
if( min1->height > 0 )
/* min1 has right subtree */
{ tmp1 = min1->right;
/* save its right tree */
min1->key = hp->key;
/* copy root into min1 */
min1->object = hp->object;
min1->height = hp->height;
min1->left = hp->left;
min1->right = hp->right;
tmp2 = merge( min1, tmp1 );
/* and merge */
}
else /* min1 is leaf on left path */
{
return_node( min1 );
return( del_obj );
}
} /* min1 is root node, has left and right subtrees */
else if ( min1->left != NULL )
tmp2 = merge( min1->left, min1->right );
Page 42 of 70
Page 43 of 70
Theorem. The binomial heap structure supports the operations insert, merge,
find min, and delete min in O(log n) time. The amortized complexity of the
insert operation is O(1); any sequence of a insert and b delete min or merge
operations on a set of heaps of initial total size n, with k heaps remaining at the
end, takes O(a + b log n + k log n) time.
Changing Keys in Heaps
In a heap data structure, the Change Key operation modifies the value of a key
at a specific position while maintaining the heap property. This operation is
commonly used in priority queues and graph algorithms like Dijkstra’s and
Prim’s algorithm.
Types of Key Changes in Heaps
1. Increase Key
o Used in max-heaps, where a key is increased, and the heap
property is restored by moving the key upward (bubble-up or sift-
up operation).
o If the new key is greater than its parent, swap it with the parent
until the max-heap property is restored.
o Time Complexity: O(log n).
2. Decrease Key
o Used in min-heaps, where a key is decreased, and the heap
property is restored by moving the key upward.
o If the new key is smaller than its parent, swap it with the parent
until the min-heap property is maintained.
o Time Complexity: O(log n).
Algorithm for Decrease Key in Min-Heap
1. Find the node whose key is to be decreased.
2. Update the key with the new smaller value.
3. Compare with the parent, and if the heap property is violated (i.e., new
key < parent key), swap the node with its parent.
4. Repeat step 3 until the heap property is restored.
Algorithm for Increase Key in Max-Heap
Page 44 of 70
Page 45 of 70
Fibonacci Heaps
A Fibonacci Heap is a type of priority queue data structure that supports a set
of operations more efficiently than binary or binomial heaps. It was introduced
by Michael Fredman and Robert Tarjan in 1984 and is used in algorithms like
Dijkstra’s shortest path algorithm and Prim’s Minimum Spanning Tree
algorithm.
Structure of a Fibonacci Heap
A Fibonacci Heap is a collection of trees that follow the min-heap or max-heap
property. The trees in the heap are unordered but follow a circular doubly
linked list structure, making operations like merging very efficient.
Key Properties of Fibonacci Heaps
1. Each tree follows the min-heap property (for a min Fibonacci Heap),
meaning the parent node is always smaller than or equal to its child
nodes.
2. It consists of a set of trees that are loosely connected.
3. The root list is a circular doubly linked list, allowing fast insertion and
union operations.
4. Each node has a degree, which is the number of its children.
5. The trees follow the property that the maximum degree (D) is
bounded by O(log n).
6. Marked nodes: A node is marked if it has lost one child. If it loses
another, it is cut from its parent and added to the root list.
Operations on Fibonacci Heaps and Their Complexities
Operation Time Complexity (Amortized)
Insert O(1)O(1)
Find Minimum O(1)O(1)
Union (Merge) O(1)O(1)
Extract Minimum O(log n)
Page 46 of 70
Page 47 of 70
Page 48 of 70
{
return( hp->right == NULL );
}
key_t find_min_key(heap_node_t *hp)
{
return( hp->left->key);
}
heap_node_t *insert(key_t new_key, object_t *new_obj, heap_node_t *hp)
{
heap_node_t *new_node;
new_node = get_node(); /* create new node */
new_node->right = NULL;
new_node->key = new_key;
new_node->object = new_obj;
new_node->rank = 0;
new_node->state = complete;
if( hp->right == NULL )
/* insert in empty heap */
{
hp->right = hp->left = hp->up = new_node;
new_node->left = NULL;
}
else /* heap nonempty, put on top of leftmost path */
{
new_node->left = hp->right;
hp->right = new_node;
new_node->left->up = new_node;
Page 49 of 70
Page 50 of 70
}
}
void decrease_key( key_t new_key, heap_node_t *n, heap_node_t *hp)
{
heap_node_t *u, *tmp; int finished = 0;
n->key = new_key; /* decrease key in n */
if( new_key < hp->left->key )
/* update min-pointer */
hp->left = n;
while( n->r_up != NULL && !finished )
{
u = n->r_up;
/* n on left path of u->right: unlink n */
if( n == u->right )
/* n on top of left path of u->right */
{
u->right = n->left;
if( n->left != NULL )
n->left->up = u;
}
else /* n further down on left path of u->right */
{
n->up->left = n->left;
if( n->left != NULL )
n->left->up = n->up;
} /* unlink n complete, now insert n on leftmost path */
n->r_up = NULL;
Page 51 of 70
Page 52 of 70
Page 53 of 70
min->right->up = hp;
min->right = NULL;
}
else /* min last node, heap now empty */
{
hp->right = NULL;
return_node( min );
return( del_obj );
}
}
}
else /* min further down on leftmost path */
{
min->up->left = min->left;
if( min->left != NULL )
/* min not last vertex */
min->left->up = min->up;
} /* unlink min complete */
/* now move left path of min->right to leftmost path */
if( min->right != NULL ) /* path nonempty */
{
tmp = min->right;
while( tmp->left != NULL )
/* find end of path */
tmp = tmp->left;
tmp->left = hp->right; tmp->left->up = tmp;
hp->right = min->right;
Page 54 of 70
min->right->up = hp;
}
/* now path below min->right linked to leftmost path */
return_node( min ); /* minimum deleted */
/* now starts clean-up phase */
for( i = 0; i < 100; i++)
rank_class[i] = NULL;
/* now unbuild leftmost path, collect nodes of equal rank*/
tmp = hp->right;
/* take first node from leftmost path */
hp->right = hp->right->left;
/* unlink that node */
while( tmp != NULL )
{
if( rank_class[tmp->rank] == NULL )
{ /* no node of same rank found: store node */
rank_class[tmp->rank] = tmp;
tmp = hp->right; /* take new node */
if( tmp != NULL)
hp->right = hp->right->left;
/* unlink that node */
}
else /* two nodes of same rank found, add blocks */
{
tmp2 = rank_class[tmp->rank];
rank_class[tmp->rank] = NULL;
if( tmp->key < tmp2->key )
Page 55 of 70
{
tmp2->left = tmp->right;
tmp->right = tmp2;
}
else /* tmp->key >= tmp2->key */
{
tmp->left = tmp2->right;
tmp2->right = tmp;
tmp = tmp2;
}
tmp->rank += 1;
/* increase rank of sum block */
}
} /* all remaining blocks now
in rank_class[] */
/* now rebuild the leftmost path */
hp->right = NULL;
for( i = 0; i < 100; i++)
{ if( rank_class[i] != NULL )
{ tmp = rank_class[i];
tmp->left = hp->right;
hp->right = tmp;
}
}
/* recompute pointers on new leftmost path */
hp->left = hp->right; tmp_min = hp->left->key;
for( tmp = hp->right; tmp->left !=NULL;
Page 56 of 70
tmp = tmp->left)
{ tmp->left->up = tmp;
/* new up pointers */
if( tmp->left->key < tmp_min )
{ hp->left = tmp->left;
/* new min pointer */
tmp_min = tmp->left->key;
}
}
hp->up = tmp; /* end of leftmost path */
/* finished with clean-up phase */
return( del_obj );
}
Heaps of Optimal Complexity
Definition:
A heap is a specialized tree-based data structure that satisfies the heap
property:
Min-Heap: The value of each parent node is smaller than or equal to the
values of its children.
Max-Heap: The value of each parent node is greater than or equal to the
values of its children.
Heaps of Optimal Complexity refer to heap structures that provide the best
possible time complexities for operations such as insertion, deletion, extract-
min, and decrease-key. Examples of such heaps include Fibonacci Heaps,
Pairing Heaps, and Brodal Heaps.
Page 58 of 70
Page 59 of 70
root with smaller key. Then it must become the root of the merged tree.
2. Compare r1->special->key and r2->key, exchange, so that
r1->key < r1->special->key < r2->key.
3. If the list of three-time occurring ranks below r1->special is not empty,
go to the first rank on the list and convert two of its nodes into the next
higher rank. Remove that rank from the list of three-time occurring ranks,
and if the next higher rank now occurs three times, add that to the list.
3.1 If that next higher rank is now the same as the rank of r1->special,
increase the rank of r1->special by one.
4. Insert r2 into the list of normal lower neighbors of r1->special at
r1->special->first.
4.1 If there were already two nodes of rank 0 on that list, combine them
into one node of rank 1.
4.2 If the rank of r1->special was 1, increase it to 2.
4.3 If there are now three nodes of rank 1 on the list, insert the first of them
in front of the list of ranks occurring three times.
Why are these Heaps Important?
They optimize key operations, making them ideal for graph algorithms
like Dijkstra’s and Prim’s algorithms.
They improve efficiency in priority queue implementations used in
networking, scheduling, and search algorithms.
Page 60 of 70
1. Min-Max Heap:
o A complete binary tree where:
Even levels maintain a min-heap property (parent ≤
children).
Odd levels maintain a max-heap property (parent ≥
children).
o Operations:
Find-Min in O(1) (root of the heap).
Find-Max in O(1) (child of root with the maximum value).
Insert, Delete-Min, and Delete-Max in O(log n).
2. Deap (Double-Ended Heap):
o A binary tree that maintains the min-heap property in one half and
the max-heap property in the other half.
o Efficient insertion, deletion, and retrieval of both minimum and
maximum elements in O(log n).
3. Interval Heap:
o A complete binary tree where each node stores an interval
[min,max][min, max].
o The left value represents the smallest element, and the right value
represents the largest element.
o Find-Min and Find-Max are both O(1), while insertion and deletion
take O(log n).
Applications of Double-Ended Heaps:
Scheduling problems (prioritizing highest and lowest urgency tasks).
Dynamic median finding (used in statistics and streaming applications).
Data compression and searching (Huffman coding, searching for largest
and smallest elements).
2. Multidimensional Heaps
Page 61 of 70
{ a min-heap,
{ a max-heap, and
{ a pairing of the elements of the min-heap and the max-heap, so that for each
pair, the min-heap element is smaller than the max-heap element, and from
any element we can access the other half of its pair in O(1).
Now the operations work as follows:
{ insert: If there is an unmatched element, the new element is paired with
it, and the smaller part of the pair is inserted into the min-heap, the larger
into the max-heap. If there is no unmatched element, the new element
becomes the unmatched element.
{ find min: Performs a find min in the min-heap and compares the
result with the unmatched element if there is one and returns the smaller.
{ find max: Performs a find max in the max-heap and compares the
result with the unmatched element if there is one and returns the larger.
{ delete min: Performs a find min in the min-heap and compares the
result with the unmatched element if there is one. If the unmatched element
is smaller, it deletes and returns the unmatched element. Otherwise it
performs a delete min in the min-heap, a general delete of the
matched element in the max-heap, and again an insert of that element
from the max-heap.
{ delete max: Performs a find max in the max-heap and compares the
result with the unmatched element if there is one. If the unmatched element
is larger, it deletes and returns the unmatched element. Otherwise it
performs a delete max in the max-heap, a general delete of the
matched element in the min-heap, and again an insert of that element
from the min-heap.
{ merge: Performs a merge for the two min-heaps and another merge for
Page 63 of 70
the two max-heaps, and if there are two unmatched elements, one from each
of the merged heaps, it matches them and inserts the smaller into the
min-heap, the larger into the max-heap.
Heap-Related Structures with Constant Time Updates
Heap-related structures with constant time updates are specialized data
structures that optimize certain operations such as insertion, decrease-key, and
merging to O(1) time complexity (amortized or worst-case). These structures
are used in applications like graph algorithms, scheduling, and priority
queues.
1. Fibonacci Heap
A collection of trees that follows the min-heap property.
Supports Decrease-Key and Insertion in O(1) amortized time.
Used in Dijkstra’s and Prim’s algorithm for efficient shortest path
calculations.
Operations and Complexities:
Operation Time Complexity (Amortized)
Insert O(1)
Find Min O(1)
Union (Merge) O(1)
Decrease Key O(1)
Extract Min O(log n)
2. Pairing Heap
A self-adjusting heap that is simpler than Fibonacci Heaps.
Provides constant-time insertion and amortized O(1) decrease-key
operation.
Used in priority queues and graph algorithms.
Operations and Complexities:
Page 64 of 70
Page 65 of 70
Page 66 of 70
entrypoint->prev->prev = entrypoint->prev;
/* minimum over empty set is +infty */
entrypoint->prev->key = POSINFTY;
/* empty minqueue created */
return( entrypoint );
}
int queue_empty(queue_t *qu)
{
return( qu->next->next == qu->next );
}
key_t find_min_key(queue_t *qu)
{
return( qu->prev->prev->key );
}
object_t *find_min_obj(queue_t *qu)
{
return( qu->prev->prev->object );
}
void enqueue( object_t *new_obj, key_t new_key, queue_t *qu)
{
queue_t *new, *tmp; tmp = NULL;
/* create and fill new node with new object and key */
new = get_node();
new->object = new_obj; new->key = new_key;
/* insert node in rear of object queue, as qu->next->next */
new->prev = qu->next;
qu->next->next->prev = new;
Page 67 of 70
new->next = qu->next->next;
qu->next->next = new;
/* remove all larger keys from rear of minkey queue */
while( qu->prev->next != qu->prev && qu->prev->next->key >
new_key)
{
if( tmp != NULL )
/* return node only if we get another*/
return_node( tmp );
tmp = qu->prev->next;
/* now unlink tmp */
qu->prev->next = tmp->next;
qu->prev->next->prev = qu->prev;
}
/* create node with new key */
new = ( tmp != NULL ) ? tmp : get_node();
new->object = new_obj; new->key = new_key;
/* insert node in rear of minkey queue, as qu->prev->next */
new->prev = qu->prev;
qu->prev->next->prev = new;
new->next = qu->prev->next;
qu->prev->next = new;
}
Page 68 of 70
Page 69 of 70
queue_t *tmp;
/* link all queues together to a list connected by next */
qu->next->prev->next = qu->prev;
qu->prev->prev->next = NULL;
/* follow the next pointers and return all nodes*/
do
{
tmp = qu->next;
return_node( qu );
qu = tmp;
}
while ( qu != NULL );
}
****************************************************************
****************************************************************
Page 70 of 70