Prerequisite - Binary Heap
K-ary heaps are a generalization of binary heap(K=2) in which each node have K children instead of 2. Just like binary heap, it follows two properties:
- Nearly complete binary tree, with all levels having maximum number of nodes except the last, which is filled in left to right manner.
- Like Binary Heap, it can be divided into two categories:
- Max k-ary heap (key at root is greater than all descendants and same is recursively true for all nodes).
- Min k-ary heap (key at root is lesser than all descendants and same is recursively true for all nodes)
Examples:
3-ary max heap - root node is maximum
of all nodes
10
/ | \
7 9 8
/ | \ /
4 6 5 7
3-ary min heap -root node is minimum
of all nodes
10
/ | \
12 11 13
/ | \
14 15 18
The height of a complete k-ary tree with n-nodes is given by logkn.
Applications of K-ary Heap:
- K-ary heap when used in the implementation of priority queue allows faster decrease key operation as compared to binary heap ( O(log2n)) for binary heap vs O(logkn) for K-ary heap). Nevertheless, it causes the complexity of extractMin() operation to increase to O(k log kn) as compared to the complexity of O(log2n) when using binary heaps for priority queue. This allows K-ary heap to be more efficient in algorithms where decrease priority operations are more common than extractMin() operation.Example: Dijkstra's algorithm for single source shortest path and Prim's algorithm for minimum spanning tree
- K-ary heap has better memory cache behaviour than a binary heap which allows them to run more quickly in practice, although it has a larger worst case running time of both extractMin() and delete() operation (both being O(k log kn) ).
Implementation:
Assuming 0 based indexing of array, an array represents a K-ary heap such that for any node we consider:
- Parent of the node at index i (except root node) is located at index (i-1)/k
- Children of the node at index i are at indices (k*i)+1 , (k*i)+2 .... (k*i)+k
- The last non-leaf node of a heap of size n is located at index (n-2)/k
buildHeap() : Builds a heap from an input array.
This function runs a loop starting from the last non-leaf node all the way upto the root node, calling a function restoreDown(also known as maHeapify) for each index that restores the passed index at the correct position of the heap by shifting the node down in the K-ary heap building it in a bottom up manner.
Why do we start the loop from the last non-leaf node ?
Because all the nodes after that are leaf nodes which will trivially satisfy the heap property as they don't have any children and hence, are already roots of a K-ary max heap.
restoreDown() (or maxHeapify) : Used to maintain heap property.
It runs a loop where it finds the maximum of all the node's children, compares it with its own value and swaps if the max(value of all children) > (value at node). It repeats this step until the node is restored into its original position in the heap.
extractMax() : Extracting the root node.
A k-ary max heap stores the largest element in its root. It returns the root node, copies last node to the first, calls restore down on the first node thus maintaining the heap property.
insert() : Inserting a node into the heap
This can be achieved by inserting the node at the last position and calling restoreUp() on the given index to restore the node at its proper position in the heap. restoreUp() iteratively compares a given node with its parent, since in a max heap the parent is always greater than or equal to its children nodes, the node is swapped with its parent only when its key is greater than the parent.
Combining the above, following is the implementation of K-ary heap.
CPP
// C++ program to demonstrate all operations of
// k-ary Heap
#include<bits/stdc++.h>
using namespace std;
// function to heapify (or restore the max- heap
// property). This is used to build a k-ary heap
// and in extractMin()
// att[] -- Array that stores heap
// len -- Size of array
// index -- index of element to be restored
// (or heapified)
void restoreDown(int arr[], int len, int index,
int k)
{
// child array to store indexes of all
// the children of given node
int child[k+1];
while (1)
{
// child[i]=-1 if the node is a leaf
// children (no children)
for (int i=1; i<=k; i++)
child[i] = ((k*index + i) < len) ?
(k*index + i) : -1;
// max_child stores the maximum child and
// max_child_index holds its index
int max_child = -1, max_child_index ;
// loop to find the maximum of all
// the children of a given node
for (int i=1; i<=k; i++)
{
if (child[i] != -1 &&
arr[child[i]] > max_child)
{
max_child_index = child[i];
max_child = arr[child[i]];
}
}
// leaf node
if (max_child == -1)
break;
// swap only if the key of max_child_index
// is greater than the key of node
if (arr[index] < arr[max_child_index])
swap(arr[index], arr[max_child_index]);
index = max_child_index;
}
}
// Restores a given node up in the heap. This is used
// in decreaseKey() and insert()
void restoreUp(int arr[], int index, int k)
{
// parent stores the index of the parent variable
// of the node
int parent = (index-1)/k;
// Loop should only run till root node in case the
// element inserted is the maximum restore up will
// send it to the root node
while (parent>=0)
{
if (arr[index] > arr[parent])
{
swap(arr[index], arr[parent]);
index = parent;
parent = (index -1)/k;
}
// node has been restored at the correct position
else
break;
}
}
// Function to build a heap of arr[0..n-1] and value of k.
void buildHeap(int arr[], int n, int k)
{
// Heapify all internal nodes starting from last
// non-leaf node all the way upto the root node
// and calling restore down on each
for (int i= (n-1)/k; i>=0; i--)
restoreDown(arr, n, i, k);
}
// Function to insert a value in a heap. Parameters are
// the array, size of heap, value k and the element to
// be inserted
void insert(int arr[], int* n, int k, int elem)
{
// Put the new element in the last position
arr[*n] = elem;
// Increase heap size by 1
*n = *n+1;
// Call restoreUp on the last index
restoreUp(arr, *n-1, k);
}
// Function that returns the key of root node of
// the heap and then restores the heap property
// of the remaining nodes
int extractMax(int arr[], int* n, int k)
{
// Stores the key of root node to be returned
int max = arr[0];
// Copy the last node's key to the root node
arr[0] = arr[*n-1];
// Decrease heap size by 1
*n = *n-1;
// Call restoreDown on the root node to restore
// it to the correct position in the heap
restoreDown(arr, *n, 0, k);
return max;
}
// Driver program
int main()
{
const int capacity = 100;
int arr[capacity] = {4, 5, 6, 7, 8, 9, 10};
int n = 7;
int k = 3;
buildHeap(arr, n, k);
printf("Built Heap : \n");
for (int i=0; i<n; i++)
printf("%d ", arr[i]);
int element = 3;
insert(arr, &n, k, element);
printf("\n\nHeap after insertion of %d: \n",
element);
for (int i=0; i<n; i++)
printf("%d ", arr[i]);
printf("\n\nExtracted max is %d",
extractMax(arr, &n, k));
printf("\n\nHeap after extract max: \n");
for (int i=0; i<n; i++)
printf("%d ", arr[i]);
return 0;
}
Java
public class KaryHeap {
public static void main(String[] args) {
final int capacity = 100;
int[] arr = new int[capacity];
arr[0] = 4;
arr[1] = 5;
arr[2] = 6;
arr[3] = 7;
arr[4] = 8;
arr[5] = 9;
arr[6] = 10;
int n = 7;
int k = 3;
buildHeap(arr, n, k);
System.out.println("Built Heap: ");
for (int i = 0; i < n; i++)
System.out.print(arr[i] + " ");
int element = 3;
insert(arr, n, k, element);
n++;
System.out.println("\n\nHeap after insertion of " + element + ": ");
for (int i = 0; i < n; i++)
System.out.print(arr[i] + " ");
System.out.println("\n\nExtracted max is " + extractMax(arr, n, k));
n--;
System.out.println("\n\nHeap after extract max: ");
for (int i = 0; i < n; i++)
System.out.print(arr[i] + " ");
}
public static void buildHeap(int[] arr, int n, int k) {
for (int i = (n - 1) / k; i >= 0; i--)
restoreDown(arr, n, i, k);
}
public static void insert(int[] arr, int n, int k, int elem) {
arr[n - 1] = elem;
restoreUp(arr, n - 1, k);
}
public static int extractMax(int[] arr, int n, int k) {
int max = arr[0];
arr[0] = arr[n - 1];
restoreDown(arr, n - 1, 0, k);
return max;
}
public static void restoreDown(int[] arr, int len, int index, int k) {
int[] child = new int[k + 1];
while (true) {
for (int i = 1; i <= k; i++)
child[i] = (k * index + i) < len ? (k * index + i) : -1;
int maxChild = -1, maxChildIndex = 0;
for (int i = 1; i <= k; i++) {
if (child[i] != -1 && arr[child[i]] > maxChild) {
maxChildIndex = child[i];
maxChild = arr[child[i]];
}
}
if (maxChild == -1)
break;
if (arr[index] < arr[maxChildIndex])
swap(arr, index, maxChildIndex);
index = maxChildIndex;
}
}
public static void restoreUp(int[] arr, int index, int k) {
int parent = (index - 1) / k;
while (parent >= 0) {
if (arr[index] > arr[parent]) {
swap(arr, index, parent);
index = parent;
parent = (index - 1) / k;
} else
break;
}
}
public static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
Python
def restore_down(arr, length, index, k):
child = [0] * (k + 1)
while True:
for i in range(1, k + 1):
child[i] = k * index + i if k * index + i < length else -1
max_child, max_child_index = -1, 0
for i in range(1, k + 1):
if child[i] != -1 and arr[child[i]] > max_child:
max_child_index = child[i]
max_child = arr[child[i]]
if max_child == -1:
break
if arr[index] < arr[max_child_index]:
arr[index], arr[max_child_index] = arr[max_child_index], arr[index]
index = max_child_index
def restore_up(arr, index, k):
parent = (index - 1) // k
while parent >= 0:
if arr[index] > arr[parent]:
arr[index], arr[parent] = arr[parent], arr[index]
index = parent
parent = (index - 1) // k
else:
break
def build_heap(arr, n, k):
for i in range((n - 1) // k, -1, -1):
restore_down(arr, n, i, k)
def insert(arr, n, k, elem):
arr.append(elem)
n += 1
restore_up(arr, n - 1, k)
def extract_max(arr, n, k):
max_elem = arr[0]
arr[0] = arr[n - 1]
n -= 1
restore_down(arr, n, 0, k)
return max_elem
arr = [4, 5, 6, 7, 8, 9, 10]
n = 7
k = 3
build_heap(arr, n, k)
print("Built Heap:")
print(arr[:n])
elem = 3
insert(arr, n, k, elem)
print("\nHeap after insertion of", elem, ":")
print(arr[:n])
max_elem = extract_max(arr, n, k)
print("\nExtracted max is", max_elem)
print("Heap after extract max:")
print(arr[:n])
C#
using System;
class KaryHeap
{
static void restoreDown(int[] arr, int len, int index, int k)
{
int[] child = new int[k + 1];
while (true)
{
for (int i = 1; i <= k; i++)
child[i] = (k * index + i) < len ? (k * index + i) : -1;
int maxChild = -1, maxChildIndex = 0;
for (int i = 1; i <= k; i++)
{
if (child[i] != -1 && arr[child[i]] > maxChild)
{
maxChildIndex = child[i];
maxChild = arr[child[i]];
}
}
if (maxChild == -1)
break;
if (arr[index] < arr[maxChildIndex])
swap(ref arr[index], ref arr[maxChildIndex]);
index = maxChildIndex;
}
}
static void restoreUp(int[] arr, int index, int k)
{
int parent = (index - 1) / k;
while (parent >= 0)
{
if (arr[index] > arr[parent])
{
swap(ref arr[index], ref arr[parent]);
index = parent;
parent = (index - 1) / k;
}
else
break;
}
}
static void buildHeap(int[] arr, int n, int k)
{
for (int i = (n - 1) / k; i >= 0; i--)
restoreDown(arr, n, i, k);
}
static void insert(int[] arr, ref int n, int k, int elem)
{
arr[n] = elem;
n++;
restoreUp(arr, n - 1, k);
}
static int extractMax(int[] arr, ref int n, int k)
{
int max = arr[0];
arr[0] = arr[n - 1];
n--;
restoreDown(arr, n, 0, k);
return max;
}
static void Main(string[] args)
{
const int capacity = 100;
int[] arr = new int[capacity] { 4, 5, 6, 7, 8, 9, 10 };
int n = 7;
int k = 3;
buildHeap(arr, n, k);
Console.WriteLine("Built Heap : ");
for (int i = 0; i < n; i++)
Console.Write("{0} ", arr[i]);
int element = 3;
insert(arr, ref n, k, element);
Console.WriteLine("\n\nHeap after insertion of {0}: ", element);
for (int i = 0; i < n; i++)
Console.Write("{0} ", arr[i]);
Console.WriteLine("\n\nExtracted max is {0}", extractMax(arr, ref n, k));
Console.WriteLine("\n\nHeap after extract max: ");
for (int i = 0; i < n; i++)
Console.Write("{0} ", arr[i]);
Console.ReadLine();
}
static void swap(ref int a, ref int b)
{
int temp = a;
a = b;
b = temp;
}
}
JavaScript
// Function to restore the max-heap property by moving the element down the heap
function restoreDown(arr, len, index, k) {
// child array to store indexes of all the children of the given node
let child = Array(k + 1).fill(-1);
while (true) {
// Initialize child array with indexes of the children
for (let i = 1; i <= k; i++) {
child[i] = k * index + i < len ? k * index + i : -1;
}
let maxChild = -1;
let maxChildIndex;
// Find the maximum child among all the children
for (let i = 1; i <= k; i++) {
if (child[i] !== -1 && arr[child[i]] > maxChild) {
maxChildIndex = child[i];
maxChild = arr[child[i]];
}
}
// If the node is a leaf node, break the loop
if (maxChild === -1) {
break;
}
// Swap only if the key of maxChild is greater than the key of the node
if (arr[index] < arr[maxChildIndex]) {
[arr[index], arr[maxChildIndex]] = [arr[maxChildIndex], arr[index]];
}
// Move to the next level of the heap
index = maxChildIndex;
}
}
// Function to restore a given node up in the heap
function restoreUp(arr, index, k) {
let parent = Math.floor((index - 1) / k);
// Move up the heap until the heap property is restored
while (parent >= 0) {
if (arr[index] > arr[parent]) {
// Swap if the key of the current node is greater than the key of its parent
[arr[index], arr[parent]] = [arr[parent], arr[index]];
index = parent;
parent = Math.floor((index - 1) / k);
} else {
// Node has been restored at the correct position
break;
}
}
}
// Function to build a heap from an array
function buildHeap(arr, n, k) {
// Heapify all internal nodes starting from the last non-leaf node up to the root node
for (let i = Math.floor((n - 1) / k); i >= 0; i--) {
restoreDown(arr, n, i, k);
}
}
// Function to insert a value into the heap
function insert(arr, n, k, elem) {
// Put the new element in the last position
arr[n[0]] = elem;
// Increase heap size by 1
n[0]++;
// Restore the heap property by moving the element up
restoreUp(arr, n[0] - 1, k);
}
// Function to extract the maximum value from the heap
function extractMax(arr, n, k) {
// Store the key of the root node to be returned
let max = arr[0];
// Copy the last node's key to the root node
arr[0] = arr[n[0] - 1];
// Decrease heap size by 1
n[0]--;
// Restore the heap property by moving the root node down
restoreDown(arr, n[0], 0, k);
return max;
}
// Driver program
const capacity = 100;
let arr = [4, 5, 6, 7, 8, 9, 10];
let n = [7]; // Using an array to simulate pass by reference for 'n'
const k = 3;
// Build the heap from the given array
buildHeap(arr, n[0], k);
console.log("Built Heap : ");
console.log(arr.slice(0, n[0]).join(" "));
const element = 3;
// Insert a new element into the heap
insert(arr, n, k, element);
console.log(`\nHeap after insertion of ${element}:`);
console.log(arr.slice(0, n[0]).join(" "));
// Extract the maximum value from the heap
console.log(`\nExtracted max is ${extractMax(arr, n, k)}`);
console.log("\nHeap after extracting max:");
console.log(arr.slice(0, n[0]).join(" "));
OutputBuilt Heap :
10 9 6 7 8 4 5
Heap after insertion of 3:
10 9 6 7 8 4 5 3
Extracted max is 10
Heap after extract max:
9 8 6 7 3 4 5
Time Complexity Analysis
- For a k-ary heap, with n nodes the maximum height of the given heap will be logkn. So restoreUp() run for maximum of logkn times (as at every iteration the node is shifted one level up is case of restoreUp() or one level down in case of restoreDown).
- restoreDown() calls itself recursively for k children. So time complexity of this functions is O(k logkn).
- Insert and decreaseKey() operations call restoreUp() once. So complexity is O(logkn).
- Since extractMax() calls restoreDown() once, its complexity O(k logkn)
- Time complexity of build heap is O(n) (Analysis is similar to binary heap)
Auxiliary Space: O(n). This is because we need to store all the elements of the heap in an array.
Similar Reads
Heap Data Structure A Heap is a complete binary tree data structure that satisfies the heap property: for every node, the value of its children is greater than or equal to its own value. Heaps are usually used to implement priority queues, where the smallest (or largest) element is always at the root of the tree.Basics
2 min read
Introduction to Heap - Data Structure and Algorithm Tutorials A Heap is a special tree-based data structure with the following properties:It is a complete binary tree (all levels are fully filled except possibly the last, which is filled from left to right).It satisfies either the max-heap property (every parent node is greater than or equal to its children) o
15+ min read
Binary Heap A Binary Heap is a complete binary tree that stores data efficiently, allowing quick access to the maximum or minimum element, depending on the type of heap. It can either be a Min Heap or a Max Heap. In a Min Heap, the key at the root must be the smallest among all the keys in the heap, and this pr
13 min read
Advantages and Disadvantages of Heap Advantages of Heap Data StructureTime Efficient: Heaps have an average time complexity of O(log n) for inserting and deleting elements, making them efficient for large datasets. We can convert any array to a heap in O(n) time. The most important thing is, we can get the min or max in O(1) timeSpace
2 min read
Time Complexity of building a heap Consider the following algorithm for building a Heap of an input array A. A quick look over the above implementation suggests that the running time is O(n * lg(n)) since each call to Heapify costs O(lg(n)) and Build-Heap makes O(n) such calls. This upper bound, though correct, is not asymptotically
2 min read
Applications of Heap Data Structure Heap Data Structure is generally taught with Heapsort. Heapsort algorithm has limited uses because Quicksort is better in practice. Nevertheless, the Heap data structure itself is enormously used. Priority Queues: Heaps are commonly used to implement priority queues, where elements with higher prior
2 min read
Comparison between Heap and Tree What is Heap? A Heap is a special Tree-based data structure in which the tree is a complete binary tree. Types of Heap Data Structure: Generally, Heaps can be of two types: Max-Heap: In a Max-Heap the key present at the root node must be greatest among the keys present at all of its children. The sa
3 min read
When building a Heap, is the structure of Heap unique? What is Heap? A heap is a tree based data structure where the tree is a complete binary tree that maintains the property that either the children of a node are less than itself (max heap) or the children are greater than the node (min heap). Properties of Heap: Structural Property: This property sta
4 min read
Some other type of Heap
Easy problems on Heap
Check if a given Binary Tree is a HeapGiven a binary tree, check if it has heap property or not, Binary tree needs to fulfil the following two conditions for being a heap: It should be a complete tree (i.e. Every level of the tree, except possibly the last, is completely filled, and all nodes are as far left as possible.).Every nodeâs v
15+ min read
How to check if a given array represents a Binary Heap?Given an array, how to check if the given array represents a Binary Max-Heap.Examples: Input: arr[] = {90, 15, 10, 7, 12, 2} Output: True The given array represents below tree 90 / \ 15 10 / \ / 7 12 2 The tree follows max-heap property as every node is greater than all of its descendants. Input: ar
11 min read
Iterative HeapSortHeapSort is a comparison-based sorting technique where we first build Max Heap and then swap the root element with the last element (size times) and maintains the heap property each time to finally make it sorted. Examples: Input : 10 20 15 17 9 21 Output : 9 10 15 17 20 21 Input: 12 11 13 5 6 7 15
11 min read
Find k largest elements in an arrayGiven an array arr[] and an integer k, the task is to find k largest elements in the given array. Elements in the output array should be in decreasing order.Examples:Input: [1, 23, 12, 9, 30, 2, 50], k = 3Output: [50, 30, 23]Input: [11, 5, 12, 9, 44, 17, 2], k = 2Output: [44, 17]Table of Content[Nai
15+ min read
Kâth Smallest Element in Unsorted ArrayGiven an array arr[] of N distinct elements and a number K, where K is smaller than the size of the array. Find the K'th smallest element in the given array. Examples:Input: arr[] = {7, 10, 4, 3, 20, 15}, K = 3 Output: 7Input: arr[] = {7, 10, 4, 3, 20, 15}, K = 4 Output: 10 Table of Content[Naive Ap
15 min read
Height of a complete binary tree (or Heap) with N nodesConsider a Binary Heap of size N. We need to find the height of it. Examples: Input : N = 6 Output : 2 () / \ () () / \ / () () () Input : N = 9 Output : 3 () / \ () () / \ / \ () () () () / \ () ()Recommended PracticeHeight of HeapTry It! Let the size of the heap be N and the height be h. If we tak
3 min read
Heap Sort for decreasing order using min heapGiven an array of elements, sort the array in decreasing order using min heap. Examples: Input : arr[] = {5, 3, 10, 1}Output : arr[] = {10, 5, 3, 1}Input : arr[] = {1, 50, 100, 25}Output : arr[] = {100, 50, 25, 1}Prerequisite: Heap sort using min heap.Using Min Heap Implementation - O(n Log n) Time
11 min read