Implement heap data structure in C++.





Prerequisite:



We have introduced heap data structure in above post and discussed heapify-up, push, heapify-down and pop operations in detail. In this post, implementation of max heap and min heap data structure is provided. Their implementation is somewhat similar to std::priority_queue .

Max Heap C++ implementation –

#include <iostream> #include <vector> #include <algorithm> #include <stdexcept> using namespace std; // Data structure for Max Heap struct PriorityQueue { private: // vector to store heap elements vector<int> A; // return parent of A[i] // don't call this function if i is already a root node int PARENT(int i) { return (i - 1) / 2; } // return left child of A[i] int LEFT(int i) { return (2 * i + 1); } // return right child of A[i] int RIGHT(int i) { return (2 * i + 2); } // Recursive Heapify-down algorithm // the node at index i and its two direct children // violates the heap property void heapify_down(int i) { // get left and right child of node at index i int left = LEFT(i); int right = RIGHT(i); int largest = i; // compare A[i] with its left and right child // and find largest value if (left < size() && A[left] > A[i]) largest = left; if (right < size() && A[right] > A[largest]) largest = right; // swap with child having greater value and // call heapify-down on the child if (largest != i) { swap(A[i], A[largest]); heapify_down(largest); } } // Recursive Heapify-up algorithm void heapify_up(int i) { // check if node at index i and its parent violates // the heap property if (i && A[PARENT(i)] < A[i]) { // swap the two if heap property is violated swap(A[i], A[PARENT(i)]); // call Heapify-up on the parent heapify_up(PARENT(i)); } } public: // return size of the heap unsigned int size() { return A.size(); } // function to check if heap is empty or not bool empty() { return size() == 0; } // insert key into the heap void push(int key) { // insert the new element to the end of the vector A.push_back(key); // get element index and call heapify-up procedure int index = size() - 1; heapify_up(index); } // function to remove element with highest priority (present at root) void pop() { try { // if heap has no elements, throw an exception if (size() == 0) throw out_of_range("Vector<X>::at() : " "index is out of range(Heap underflow)"); // replace the root of the heap with the last element // of the vector A[0] = A.back(); A.pop_back(); // call heapify-down on root node heapify_down(0); } // catch and print the exception catch (const out_of_range& oor) { cout << "

" << oor.what(); } } // function to return element with highest priority (present at root) int top() { try { // if heap has no elements, throw an exception if (size() == 0) throw out_of_range("Vector<X>::at() : " "index is out of range(Heap underflow)"); // else return the top (first) element return A.at(0); // or return A[0]; } // catch and print the exception catch (const out_of_range& oor) { cout << "

" << oor.what(); } } }; // Max Heap C++ implementation int main() { PriorityQueue pq; // Note - Priority is decided by element's value pq.push(3); pq.push(2); pq.push(15); cout << "Size is " << pq.size() << endl; cout << pq.top() << " "; pq.pop(); cout << pq.top() << " "; pq.pop(); pq.push(5); pq.push(4); pq.push(45); cout << endl << "Size is " << pq.size() << endl; cout << pq.top() << " "; pq.pop(); cout << pq.top() << " "; pq.pop(); cout << pq.top() << " "; pq.pop(); cout << pq.top() << " "; pq.pop(); cout << endl << std::boolalpha << pq.empty(); pq.top(); // top operation on an empty heap pq.pop(); // pop operation on an empty heap return 0; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 #include <iostream> #include <vector> #include <algorithm> #include <stdexcept> using namespace std ; // Data structure for Max Heap struct PriorityQueue { private : // vector to store heap elements vector < int > A ; // return parent of A[i] // don't call this function if i is already a root node int PARENT ( int i ) { return ( i - 1 ) / 2 ; } // return left child of A[i] int LEFT ( int i ) { return ( 2 * i + 1 ) ; } // return right child of A[i] int RIGHT ( int i ) { return ( 2 * i + 2 ) ; } // Recursive Heapify-down algorithm // the node at index i and its two direct children // violates the heap property void heapify_down ( int i ) { // get left and right child of node at index i int left = LEFT ( i ) ; int right = RIGHT ( i ) ; int largest = i ; // compare A[i] with its left and right child // and find largest value if ( left < size ( ) && A [ left ] > A [ i ] ) largest = left ; if ( right < size ( ) && A [ right ] > A [ largest ] ) largest = right ; // swap with child having greater value and // call heapify-down on the child if ( largest != i ) { swap ( A [ i ] , A [ largest ] ) ; heapify_down ( largest ) ; } } // Recursive Heapify-up algorithm void heapify_up ( int i ) { // check if node at index i and its parent violates // the heap property if ( i && A [ PARENT ( i ) ] < A [ i ] ) { // swap the two if heap property is violated swap ( A [ i ] , A [ PARENT ( i ) ] ) ; // call Heapify-up on the parent heapify_up ( PARENT ( i ) ) ; } } public : // return size of the heap unsigned int size ( ) { return A . size ( ) ; } // function to check if heap is empty or not bool empty ( ) { return size ( ) == 0 ; } // insert key into the heap void push ( int key ) { // insert the new element to the end of the vector A . push_back ( key ) ; // get element index and call heapify-up procedure int index = size ( ) - 1 ; heapify_up ( index ) ; } // function to remove element with highest priority (present at root) void pop ( ) { try { // if heap has no elements, throw an exception if ( size ( ) == 0 ) throw out_of_range ( "Vector<X>::at() : " "index is out of range(Heap underflow)" ) ; // replace the root of the heap with the last element // of the vector A [ 0 ] = A . back ( ) ; A . pop_back ( ) ; // call heapify-down on root node heapify_down ( 0 ) ; } // catch and print the exception catch ( const out_of_range & oor ) { cout << "

" << oor . what ( ) ; } } // function to return element with highest priority (present at root) int top ( ) { try { // if heap has no elements, throw an exception if ( size ( ) == 0 ) throw out_of_range ( "Vector<X>::at() : " "index is out of range(Heap underflow)" ) ; // else return the top (first) element return A . at ( 0 ) ; // or return A[0]; } // catch and print the exception catch ( const out_of_range & oor ) { cout << "

" << oor . what ( ) ; } } } ; // Max Heap C++ implementation int main ( ) { PriorityQueue pq ; // Note - Priority is decided by element's value pq . push ( 3 ) ; pq . push ( 2 ) ; pq . push ( 15 ) ; cout << "Size is " << pq . size ( ) << endl ; cout << pq . top ( ) << " " ; pq . pop ( ) ; cout << pq . top ( ) << " " ; pq . pop ( ) ; pq . push ( 5 ) ; pq . push ( 4 ) ; pq . push ( 45 ) ; cout << endl << "Size is " << pq . size ( ) << endl ; cout << pq . top ( ) << " " ; pq . pop ( ) ; cout << pq . top ( ) << " " ; pq . pop ( ) ; cout << pq . top ( ) << " " ; pq . pop ( ) ; cout << pq . top ( ) << " " ; pq . pop ( ) ; cout << endl << std :: boolalpha << pq . empty ( ) ; pq . top ( ) ; // top operation on an empty heap pq . pop ( ) ; // pop operation on an empty heap return 0 ; }

Download Run Code

Output:



Size is 3

15 3

Size is 4

45 5 4 2

true

Vector ::at() : index is out of range(Heap underflow)

Vector ::at() : index is out of range(Heap underflow)



Min Heap C++ Implementation –

The min heap implementation is very similar to max heap implementation discussed above. The highlighted portion in the below code marks its differences with max heap implementation.

#include <iostream> #include <vector> #include <algorithm> #include <stdexcept> using namespace std; // Data structure for Min Heap struct PriorityQueue { private: // vector to store heap elements vector<int> A; // return parent of A[i] // don't call this function if i is already a root node int PARENT(int i) { return (i - 1) / 2; } // return left child of A[i] int LEFT(int i) { return (2 * i + 1); } // return right child of A[i] int RIGHT(int i) { return (2 * i + 2); } // Recursive Heapify-down algorithm // the node at index i and its two direct children // violates the heap property void heapify_down(int i) { // get left and right child of node at index i int left = LEFT(i); int right = RIGHT(i); int smallest = i; // compare A[i] with its left and right child // and find smallest value if (left < size() && A[left] < A[i]) smallest = left; if (right < size() && A[right] < A[smallest]) smallest = right; // swap with child having lesser value and // call heapify-down on the child if (smallest != i) { swap(A[i], A[smallest]); heapify_down(smallest); } } // Recursive Heapify-up algorithm void heapify_up(int i) { // check if node at index i and its parent violates // the heap property if (i && A[PARENT(i)] > A[i]) { // swap the two if heap property is violated swap(A[i], A[PARENT(i)]); // call Heapify-up on the parent heapify_up(PARENT(i)); } } public: // return size of the heap unsigned int size() { return A.size(); } // function to check if heap is empty or not bool empty() { return size() == 0; } // insert key into the heap void push(int key) { // insert the new element to the end of the vector A.push_back(key); // get element index and call heapify-up procedure int index = size() - 1; heapify_up(index); } // function to remove element with lowest priority (present at root) void pop() { try { // if heap has no elements, throw an exception if (size() == 0) throw out_of_range("Vector<X>::at() : " "index is out of range(Heap underflow)"); // replace the root of the heap with the last element // of the vector A[0] = A.back(); A.pop_back(); // call heapify-down on root node heapify_down(0); } // catch and print the exception catch (const out_of_range& oor) { cout << "

" << oor.what(); } } // function to return element with lowest priority (present at root) int top() { try { // if heap has no elements, throw an exception if (size() == 0) throw out_of_range("Vector<X>::at() : " "index is out of range(Heap underflow)"); // else return the top (first) element return A.at(0); // or return A[0]; } // catch and print the exception catch (const out_of_range& oor) { cout << "

" << oor.what(); } } }; // Min Heap C++ Implementation int main() { PriorityQueue pq; // Note - Priority is decided by element's value pq.push(3); pq.push(2); pq.push(15); cout << "Size is " << pq.size() << endl; cout << pq.top() << " "; pq.pop(); cout << pq.top() << " "; pq.pop(); pq.push(5); pq.push(4); pq.push(45); cout << endl << "Size is " << pq.size() << endl; cout << pq.top() << " "; pq.pop(); cout << pq.top() << " "; pq.pop(); cout << pq.top() << " "; pq.pop(); cout << pq.top() << " "; pq.pop(); cout << endl << std::boolalpha << pq.empty(); pq.top(); // top operation on an empty heap pq.pop(); // pop operation on an empty heap return 0; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 #include <iostream> #include <vector> #include <algorithm> #include <stdexcept> using namespace std ; // Data structure for Min Heap struct PriorityQueue { private : // vector to store heap elements vector < int > A ; // return parent of A[i] // don't call this function if i is already a root node int PARENT ( int i ) { return ( i - 1 ) / 2 ; } // return left child of A[i] int LEFT ( int i ) { return ( 2 * i + 1 ) ; } // return right child of A[i] int RIGHT ( int i ) { return ( 2 * i + 2 ) ; } // Recursive Heapify-down algorithm // the node at index i and its two direct children // violates the heap property void heapify_down ( int i ) { // get left and right child of node at index i int left = LEFT ( i ) ; int right = RIGHT ( i ) ; int smallest = i ; // compare A[i] with its left and right child // and find smallest value if ( left < size ( ) && A [ left ] < A [ i ] ) smallest = left ; if ( right < size ( ) && A [ right ] < A [ smallest ] ) smallest = right ; // swap with child having lesser value and // call heapify-down on the child if ( smallest != i ) { swap ( A [ i ] , A [ smallest ] ) ; heapify_down ( smallest ) ; } } // Recursive Heapify-up algorithm void heapify_up ( int i ) { // check if node at index i and its parent violates // the heap property if ( i && A [ PARENT ( i ) ] > A [ i ] ) { // swap the two if heap property is violated swap ( A [ i ] , A [ PARENT ( i ) ] ) ; // call Heapify-up on the parent heapify_up ( PARENT ( i ) ) ; } } public : // return size of the heap unsigned int size ( ) { return A . size ( ) ; } // function to check if heap is empty or not bool empty ( ) { return size ( ) == 0 ; } // insert key into the heap void push ( int key ) { // insert the new element to the end of the vector A . push_back ( key ) ; // get element index and call heapify-up procedure int index = size ( ) - 1 ; heapify_up ( index ) ; } // function to remove element with lowest priority (present at root) void pop ( ) { try { // if heap has no elements, throw an exception if ( size ( ) == 0 ) throw out_of_range ( "Vector<X>::at() : " "index is out of range(Heap underflow)" ) ; // replace the root of the heap with the last element // of the vector A [ 0 ] = A . back ( ) ; A . pop_back ( ) ; // call heapify-down on root node heapify_down ( 0 ) ; } // catch and print the exception catch ( const out_of_range & oor ) { cout << "

" << oor . what ( ) ; } } // function to return element with lowest priority (present at root) int top ( ) { try { // if heap has no elements, throw an exception if ( size ( ) == 0 ) throw out_of_range ( "Vector<X>::at() : " "index is out of range(Heap underflow)" ) ; // else return the top (first) element return A . at ( 0 ) ; // or return A[0]; } // catch and print the exception catch ( const out_of_range & oor ) { cout << "

" << oor . what ( ) ; } } } ; // Min Heap C++ Implementation int main ( ) { PriorityQueue pq ; // Note - Priority is decided by element's value pq . push ( 3 ) ; pq . push ( 2 ) ; pq . push ( 15 ) ; cout << "Size is " << pq . size ( ) << endl ; cout << pq . top ( ) << " " ; pq . pop ( ) ; cout << pq . top ( ) << " " ; pq . pop ( ) ; pq . push ( 5 ) ; pq . push ( 4 ) ; pq . push ( 45 ) ; cout << endl << "Size is " << pq . size ( ) << endl ; cout << pq . top ( ) << " " ; pq . pop ( ) ; cout << pq . top ( ) << " " ; pq . pop ( ) ; cout << pq . top ( ) << " " ; pq . pop ( ) ; cout << pq . top ( ) << " " ; pq . pop ( ) ; cout << endl << std :: boolalpha << pq . empty ( ) ; pq . top ( ) ; // top operation on an empty heap pq . pop ( ) ; // pop operation on an empty heap return 0 ; }

Download Run Code

Output:



Size is 3

2 3

Size is 4

4 5 15 45

true

Vector ::at() : index is out of range(Heap underflow)

Vector ::at() : index is out of range(Heap underflow)





The time complexity of push()/pop() operations is O(log(n)) and peek()/size()/empty() operations is O(1) .



Exercise: Convert above code to use array instead of vector (check simple solution here).

Also See:



References: https://en.wikipedia.org/wiki/Heap_(data_structure)









(52 votes, average: 4.69 out of 5)

Loading...

Thanks for reading.