K-th Greatest Element in a Max-Heap - GeeksforGeeks

26 Nov, 2018
Given a max-heap of size n, find the kth greatest element in the max-heap.
Examples:
Input : maxHeap = {20, 15, 18, 8, 10, 5, 17}k = 4Output : 15
Input : maxHeap = {100, 50, 80, 10, 25, 20, 75}k = 2Output : 80
Naive approach: We can extract the maximum element from the max-heap k times and the last element extracted will be the kth greatest element. Each deletion operations takes O(log n) time, so the total time complexity of this approach comes out to be O(k * log n).
Below is the implementation of this approach:
// C++ program for the// above approach#include <bits/stdc++.h>using namespace std;  // Structure for the heapstruct Heap {    vector<int> v;    int n; // Size of the heap      Heap(int i = 0)        : n(i)    {        v = vector<int>(n);    }};  // Generic function to// swap two integersvoid swap(int& a, int& b){    int temp = a;    a = b;    b = temp;}  // Returns the index of// the parent nodeinline int parent(int i){    return (i - 1) / 2;}  // Returns the index of// the left child nodeinline int left(int i){    return 2 * i + 1;}  // Returns the index of// the right child nodeinline int right(int i){    return 2 * i + 2;}  // Maintains the heap propertyvoid heapify(Heap& h, int i){    int l = left(i), r = right(i), m = i;    if (l < h.n && h.v[i] < h.v[l])        m = l;    if (r < h.n && h.v[m] < h.v[r])        m = r;    if (m != i) {        swap(h.v[m], h.v[i]);        heapify(h, m);    }}  // Extracts the maximum elementint extractMax(Heap& h){    if (!h.n)        return -1;    int m = h.v[0];    h.v[0] = h.v[h.n-- - 1];    heapify(h, 0);    return m;}  int kThGreatest(Heap &h, int k){    for (int i = 1; i < k; ++i)        extractMax(h);    return extractMax(h);}  // Driver Codeint main(){    Heap h(7);    h.v = vector<int>{ 20, 15, 18, 8, 10, 5, 17 };    int k = 4;      cout << kThGreatest(h, k);    return 0;}
15

Time Complexity: O(k * log n)
Efficient approach: We can note an interesting observation about max-heap. An element x at ith level has i – 1 ancestors. By the property of max-heaps, these i – 1 ancestors are guaranteed to be greater than x. This implies that x cannot be among the greatest i – 1 elements of the heap. Using this property, we can conclude that the kth greatest element can have a level of at most k.
We can reduce the size of the max-heap such that it has only k levels. We can then obtain the kth greatest element by our previous strategy of extracting the maximum element k times. Note that the size of the heap is reduced to a maximum of 2k – 1, therefore each heapify operation will take O(log 2k) = O(k) time. The total time complexity will be O(k2). If n >> k, then this approach performs better than the previous one.
Below is the implementation of this approach:
// C++ program for the// above approach#include <bits/stdc++.h>using namespace std;  // Structure for the heapstruct Heap {    vector<int> v;    int n; // Size of the heap      Heap(int i = 0)        : n(i)    {        v = vector<int>(n);    }};  // Generic function to// swap two integersvoid swap(int& a, int& b){    int temp = a;    a = b;    b = temp;}  // Returns the index of// the parent nodeinline int parent(int i){    return (i - 1) / 2;}  // Returns the index of// the left child nodeinline int left(int i){    return 2 * i + 1;}  // Returns the index of// the right child nodeinline int right(int i){    return 2 * i + 2;}  // Maintains the heap propertyvoid heapify(Heap& h, int i){    int l = left(i), r = right(i), m = i;    if (l < h.n && h.v[i] < h.v[l])        m = l;    if (r < h.n && h.v[m] < h.v[r])        m = r;    if (m != i) {        swap(h.v[m], h.v[i]);        heapify(h, m);    }}  // Extracts the maximum elementint extractMax(Heap& h){    if (!h.n)        return -1;    int m = h.v[0];    h.v[0] = h.v[h.n-- - 1];    heapify(h, 0);    return m;}  int kThGreatest(Heap &h, int k){    // Change size of heap    h.n = min(h.n, int(pow(2, k) - 1));      for (int i = 1; i < k; ++i)        extractMax(h);      return extractMax(h);}  // Driver Codeint main(){    Heap h(7);    h.v = vector<int>{ 20, 15, 18, 8, 10, 5, 17 };    int k = 2;      cout << kThGreatest(h, k);    return 0;}
18

Time Complexity: O(k2)
More efficient approach: We can further improve the time complexity of this problem by the following algorithm:
Create a priority queue P and insert the root node of the max-heap into P.Repeat these steps k – 1 times:Pop the greatest element from P.Insert left and right child elements of the popped element. (if they exist).The greatest element in P is the kth greatest element of the max-heap.
Create a priority queue P and insert the root node of the max-heap into P.
Repeat these steps k – 1 times:Pop the greatest element from P.Insert left and right child elements of the popped element. (if they exist).
Pop the greatest element from P.Insert left and right child elements of the popped element. (if they exist).
Pop the greatest element from P.
Insert left and right child elements of the popped element. (if they exist).
The greatest element in P is the kth greatest element of the max-heap.
The initial size of the priority queue is one, and it increases by at most one at each of the k – 1 steps. Therefore, there are maximum k elements in the priority queue and the time complexity of the pop and insert operations is O(log k). Thus the total time complexity is O(k * log k).
Below is the implementation of the above approach:
// C++ program for the// above approach#include <bits/stdc++.h>using namespace std;  // Structure for the heapstruct Heap {    vector<int> v;    int n; // Size of the heap      Heap(int i = 0)        : n(i)    {        v = vector<int>(n);    }};  // Returns the index of// the left child nodeinline int left(int i){    return 2 * i + 1;}  // Returns the index of// the right child nodeinline int right(int i){    return 2 * i + 2;}  int kThGreatest(Heap &h, int k){    priority_queue<pair<int, int> > p;    p.push(make_pair(h.v[0], 0));      for (int i = 0; i < k - 1; ++i) {        int j = p.top().second;        p.pop();        int l = left(j), r = right(j);        if (l < h.n)            p.push(make_pair(h.v[l], l));        if (r < h.n)            p.push(make_pair(h.v[r], r));    }    return p.top().first;}  // Driver Codeint main(){    Heap h(7);    h.v = vector<int>{ 20, 15, 18, 8, 10, 5, 17 };    int k = 2;      cout << kThGreatest(h, k);    return 0;}
18

Time Complexity: O(k * log k)
priority-queue
Technical Scripter 2018
Heap
Queue
Technical Scripter
Queue
Heap
priority-queue
Writing code in comment?
Please use ide.geeksforgeeks.org,
generate link and share the link here.
Insertion and Deletion in Heaps
Priority Queue in Python
Priority Queue using Binary Heap
Median in a stream of integers (running integers)
Real-time application of Data Structures
Breadth First Search or BFS for a Graph
Level Order Binary Tree Traversal
Queue Interface In Java
Queue in Python
Queue | Set 1 (Introduction and Array Implementation)