Open In App

K-th Greatest Element in a Max-Heap

Improve
Improve
Like Article
Like
Save
Share
Report

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 = 4 
Output : 15 

Input : maxHeap = {100, 50, 80, 10, 25, 20, 75} k = 2 
Output : 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++




// C++ program for the
// above approach
#include <bits/stdc++.h>
using namespace std;
 
// Structure for the heap
struct 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 integers
void swap(int& a, int& b)
{
    int temp = a;
    a = b;
    b = temp;
}
 
// Returns the index of
// the parent node
inline int parent(int i) { return (i - 1) / 2; }
 
// Returns the index of
// the left child node
inline int left(int i) { return 2 * i + 1; }
 
// Returns the index of
// the right child node
inline int right(int i) { return 2 * i + 2; }
 
// Maintains the heap property
void 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 element
int 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 Code
int main()
{
    Heap h(7);
    h.v = vector<int>{ 20, 15, 18, 8, 10, 5, 17 };
    int k = 4;
 
    cout << kThGreatest(h, k);
    return 0;
}


Java




import java.util.*;
 
class Heap
{
  ArrayList<Integer> v;
  int n; // Size of the heap
 
  Heap(int i) {
    n = i;
    v = new ArrayList<>(n);
  }
}
 
class Gfg
{
  // Generic function to
  // swap two integers
  static void swap(ArrayList<Integer> arr, int a, int b) {
    int temp = arr.get(a);
    arr.set(a,arr.get(b));
    arr.set(b,temp);
  }
 
  // Returns the index of
  // the parent node
  static int parent(int i) {
    return (i - 1) / 2;
  }
 
  // Returns the index of
  // the left child node
  static int left(int i) {
    return 2 * i + 1;
  }
 
  // Returns the index of
  // the right child node
  static int right(int i) {
    return 2 * i + 2;
  }
 
  // Maintains the heap property
  static void heapify(Heap h, int i) {
    int l = left(i), r = right(i), m = i;
    if (l < h.n && h.v.get(i) < h.v.get(l))
      m = l;
    if (r < h.n && h.v.get(m) < h.v.get(r))
      m = r;
    if (m != i) {
      swap(h.v, m, i);
      heapify(h, m);
    }
  }
 
  // Extracts the maximum element
  static int extractMax(Heap h) {
    if (h.n == 0)
      return -1;
    int m = h.v.get(0);
    h.v.set(0, h.v.get(h.n-- - 1));
    heapify(h, 0);
    return m;
  }
 
  static int kThGreatest(Heap h, int k) {
    for (int i = 1; i < k; ++i)
      extractMax(h);
    return extractMax(h);
  }
 
  // Driver Code
  public static void main(String[] args) {
    Heap h = new Heap(7);
    h.v = new ArrayList<>(Arrays.asList(20, 15, 18, 8, 10, 5, 17));
    int k = 4;
 
    System.out.println(kThGreatest(h, k));
  }
}


Python3




# Python code for the above approach
 
class Heap:
    def __init__(self, arr):
        self.arr = arr
        self.n = len(arr)
 
    def swap(self, i, j):
        self.arr[i], self.arr[j] = self.arr[j], self.arr[i]
 
    def parent(self, i):
        return (i - 1) // 2
 
    def left(self, i):
        return 2 * i + 1
 
    def right(self, i):
        return 2 * i + 2
 
    def heapify(self, i):
        l = self.left(i)
        r = self.right(i)
        m = i
 
        if l < self.n and self.arr[i] < self.arr[l]:
            m = l
        if r < self.n and self.arr[m] < self.arr[r]:
            m = r
        if m != i:
            self.swap(m, i)
            self.heapify(m)
 
    def extractMax(self):
        if not self.n:
            return -1
 
        m = self.arr[0]
        self.arr[0] = self.arr[self.n - 1]
        self.n -= 1
        self.heapify(0)
 
        return m
 
 
def kthGreatest(arr, k):
    h = Heap(arr)
 
    for i in range(1, k):
        h.extractMax()
 
    return h.extractMax()
 
 
# Driver Code
arr = [20, 15, 18, 8, 10, 5, 17]
k = 4
 
print(kthGreatest(arr, k))
 
 
# This code is contributed by prince


C#




using System;
using System.Collections.Generic;
 
class Heap
{
  public List<int> v;
  public int n; // Size of the heap
 
  public Heap(int i) {
    n = i;
    v = new List<int>(n);
  }
}
 
class Gfg
{
  // Generic function to
  // swap two integers
  static void swap(List<int> arr, int a, int b) {
    int temp = arr[a];
    arr[a] = arr[b];
    arr[b] = temp;
  }
 
  // Returns the index of
  // the parent node
  static int parent(int i) {
    return (i - 1) / 2;
  }
 
  // Returns the index of
  // the left child node
  static int left(int i) {
    return 2 * i + 1;
  }
 
  // Returns the index of
  // the right child node
  static int right(int i) {
    return 2 * i + 2;
  }
 
  // Maintains the heap property
  static void 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, i);
      heapify(h, m);
    }
  }
 
  // Extracts the maximum element
  static int extractMax(Heap h) {
    if (h.n == 0)
      return -1;
    int m = h.v[0];
    h.v[0] = h.v[h.n-- - 1];
    heapify(h, 0);
    return m;
  }
 
  static int kThGreatest(Heap h, int k) {
    for (int i = 1; i < k; ++i)
      extractMax(h);
    return extractMax(h);
  }
 
  // Driver Code
  public static void Main(string[] args) {
    Heap h = new Heap(7);
    h.v = new List<int>(new int[] {20, 15, 18, 8, 10, 5, 17});
    int k = 4;
 
    Console.WriteLine(kThGreatest(h, k));
  }
}


Javascript




class Heap {
  constructor(arr) {
    this.arr = arr;
    this.n = arr.length;
  }
 
  swap(i, j) {
    const temp = this.arr[i];
    this.arr[i] = this.arr[j];
    this.arr[j] = temp;
  }
 
  parent(i) {
    return Math.floor((i - 1) / 2);
  }
 
  left(i) {
    return 2 * i + 1;
  }
 
  right(i) {
    return 2 * i + 2;
  }
 
  heapify(i) {
    let l = this.left(i);
    let r = this.right(i);
    let m = i;
 
    if (l < this.n && this.arr[i] < this.arr[l]) {
      m = l;
    }
    if (r < this.n && this.arr[m] < this.arr[r]) {
      m = r;
    }
    if (m !== i) {
      this.swap(m, i);
      this.heapify(m);
    }
  }
 
  extractMax() {
    if (!this.n) {
      return -1;
    }
 
    let m = this.arr[0];
    this.arr[0] = this.arr[this.n-- - 1];
    this.heapify(0);
 
    return m;
  }
}
 
function kthGreatest(arr, k) {
  const h = new Heap(arr);
 
  for (let i = 1; i < k; i++) {
    h.extractMax();
  }
 
  return h.extractMax();
}
 
// Driver Code
const arr = [20, 15, 18, 8, 10, 5, 17];
const k = 4;
 
console.log(kthGreatest(arr, k));


Output

15




Complexity Analysis:

  • Time Complexity: O(k * log n) 
  • Auxiliary Space: O(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++




// C++ program for the
// above approach
#include <bits/stdc++.h>
using namespace std;
 
// Structure for the heap
struct 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 integers
void swap(int& a, int& b)
{
    int temp = a;
    a = b;
    b = temp;
}
 
// Returns the index of
// the parent node
inline int parent(int i) { return (i - 1) / 2; }
 
// Returns the index of
// the left child node
inline int left(int i) { return 2 * i + 1; }
 
// Returns the index of
// the right child node
inline int right(int i) { return 2 * i + 2; }
 
// Maintains the heap property
void 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 element
int 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 Code
int main()
{
    Heap h(7);
    h.v = vector<int>{ 20, 15, 18, 8, 10, 5, 17 };
    int k = 2;
 
    cout << kThGreatest(h, k);
    return 0;
}


Java




import java.util.*;
 
class Heap {
  ArrayList<Integer> v;
  int n; // Size of the heap
 
  Heap(int i) {
    n = i;
    v = new ArrayList<>(n);
  }
}
 
class Main {
 
  // Generic function to
  // swap two integers
  static void swap(ArrayList<Integer> arr, int a, int b) {
    int temp = arr.get(a);
    arr.set(a,arr.get(b));
    arr.set(b,temp);
  }
 
  // Returns the index of
  // the parent node
  static int parent(int i) { return (i - 1) / 2; }
 
  // Returns the index of
  // the left child node
  static int left(int i) { return 2 * i + 1; }
 
  // Returns the index of
  // the right child node
  static int right(int i) { return 2 * i + 2; }
 
  // Maintains the heap property
  static void heapify(Heap h, int i) {
    int l = left(i), r = right(i), m = i;
    if (l < h.n && h.v.get(i) < h.v.get(l))
      m = l;
    if (r < h.n && h.v.get(m) < h.v.get(r))
      m = r;
    if (m != i) {
      swap(h.v, m, i);
      heapify(h, m);
    }
  }
 
  // Extracts the maximum element
  static int extractMax(Heap h) {
    if (h.n == 0)
      return -1;
    int m = h.v.get(0);
    h.v.set(0, h.v.get(h.n-- - 1));
    heapify(h, 0);
    return m;
  }
 
  static int kThGreatest(Heap h, int k) {
    // Change size of heap
    h.n = Math.min(h.n, (int) Math.pow(2, k) - 1);
 
    for (int i = 1; i < k; ++i)
      extractMax(h);
 
    return extractMax(h);
  }
 
  public static void main(String[] args) {
    Heap h = new Heap(7);
    h.v = new ArrayList<>(Arrays.asList(20, 15, 18, 8, 10, 5, 17));
    int k = 2;
 
    System.out.println(kThGreatest(h, k));
  }
}


Python3




# Structure for the heap
class Heap:
    def __init__(self, i=0):
        self.v = [0] * i
        self.n = # Size of the heap
 
# Generic function to
# swap two integers
def swap(a, b):
    temp = a
    a = b
    b = temp
 
# Returns the index of
# the parent node
def parent(i):
    return (i - 1) // 2
 
# Returns the index of
# the left child node
def left(i):
    return 2 * i + 1
 
# Returns the index of
# the right child node
def right(i):
    return 2 * i + 2
 
# Maintains the heap property
def heapify(h, i):
    l, r, m = left(i), right(i), i
    if l < h.n and h.v[i] < h.v[l]:
        m = l
    if r < h.n and h.v[m] < h.v[r]:
        m = r
    if m != i:
        h.v[m], h.v[i] = h.v[i], h.v[m]
        heapify(h, m)
 
# Extracts the maximum element
def extractMax(h):
    if not h.n:
        return -1
    m = h.v[0]
    h.v[0] = h.v[h.n-1]
    h.n -= 1
    heapify(h, 0)
    return m
 
def kThGreatest(h, k):
    # Change size of heap
    h.n = min(h.n, 2**k - 1)
 
    for i in range(1, k):
        extractMax(h)
 
    return extractMax(h)
 
# Driver Code
if __name__ == '__main__':
    h = Heap(7)
    h.v = [20, 15, 18, 8, 10, 5, 17]
    k = 2
 
    print(kThGreatest(h, k))


C#




using System;
using System.Collections.Generic;
 
// Structure for the heap
public class Heap
{
    public List<int> v;
    public int n; // Size of the heap
 
    public Heap(int i = 0)
    {
        n = i;
        v = new List<int>(n);
    }
}
 
public class Program
{
    // Generic function to swap two integers
    static void Swap(List<int> list, int a, int b)
    {
        int temp = list[a];
        list[a] = list[b];
        list[b] = temp;
    }
 
    // Returns the index of the parent node
    static int Parent(int i) { return (i - 1) / 2; }
 
    // Returns the index of the left child node
    static int Left(int i) { return 2 * i + 1; }
 
    // Returns the index of the right child node
    static int Right(int i) { return 2 * i + 2; }
 
    // Maintains the heap property
    static void 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, i);
            Heapify(h, m);
        }
    }
 
    // Extracts the maximum element
    static int ExtractMax(Heap h)
    {
        if (h.n == 0)
            return -1;
        int m = h.v[0];
        h.v[0] = h.v[h.n-- - 1];
        Heapify(h, 0);
        return m;
    }
 
    // Finds the k-th greatest element in the heap
    static int KthGreatest(Heap h, int k)
    {
        // Change size of heap
        h.n = Math.Min(h.n, (int)Math.Pow(2, k) - 1);
 
        for (int i = 1; i < k; ++i)
            ExtractMax(h);
 
        return ExtractMax(h);
    }
 
    // Driver Code
    static void Main()
    {
        Heap h = new Heap(7);
        h.v = new List<int> { 20, 15, 18, 8, 10, 5, 17 };
        int k = 2;
 
        Console.WriteLine(KthGreatest(h, k));
    }
}


Javascript




// JavaScript program for the above approach
 
class Heap {
  constructor(i = 0) {
    this.v = new Array(i).fill(0);
    this.n = i; // Size of the heap
  }
}
 
// Generic function to
// swap two integers
function swap(a, b) {
  let temp = a;
  a = b;
  b = temp;
}
 
// Returns the index of
// the parent node
function parent(i) {
  return Math.floor((i - 1) / 2);
}
 
// Returns the index of
// the left child node
function left(i) {
  return 2 * i + 1;
}
 
// Returns the index of
// the right child node
function right(i) {
  return 2 * i + 2;
}
 
// Maintains the heap property
function heapify(h, i) {
  let l = left(i);
  let r = right(i);
  let 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) {
    [h.v[m], h.v[i]] = [h.v[i], h.v[m]];
    heapify(h, m);
  }
}
 
// Extracts the maximum element
function extractMax(h) {
  if (!h.n) {
    return -1;
  }
  let m = h.v[0];
  h.v[0] = h.v[h.n - 1];
  h.n--;
  heapify(h, 0);
  return m;
}
 
function kThGreatest(h, k) {
  // Change size of heap
  h.n = Math.min(h.n, 2 ** k - 1);
 
  for (let i = 1; i < k; i++) {
    extractMax(h);
  }
 
  return extractMax(h);
}
 
// Driver Code
let h = new Heap(7);
h.v = [20, 15, 18, 8, 10, 5, 17];
let k = 2;
 
console.log(kThGreatest(h, k));
 
// This code is contributed by princekumaras


Output

18




Complexity Analysis:

  • Time Complexity: O(k2
  • Auxiliary Space: O(n)

More efficient approach

We can further improve the time complexity of this problem by the following algorithm:

  1. Create a priority queue P and insert the root node of the max-heap into P.
  2. Repeat these steps k – 1 times:
    1. Pop the greatest element from P.
    2. Insert left and right child elements of the popped element. (if they exist).
  3. 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: 

Implementation:

C++




// C++ program for the
// above approach
#include <bits/stdc++.h>
using namespace std;
 
// Structure for the heap
struct 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 node
inline int left(int i) { return 2 * i + 1; }
 
// Returns the index of
// the right child node
inline 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 Code
int main()
{
    Heap h(7);
    h.v = vector<int>{ 20, 15, 18, 8, 10, 5, 17 };
    int k = 2;
 
    cout << kThGreatest(h, k);
    return 0;
}


Java




/*package whatever //do not write package name here */
 
import java.util.*;
 
class Heap {
    ArrayList<Integer> v;
    int n;
 
    Heap(int i)
    {
        n = i;
        v = new ArrayList<>(n);
    }
}
 
public class Main {
    // Returns the index of the left child node
    static int left(int i) { return 2 * i + 1; }
 
    // Returns the index of the right child node
    static int right(int i) { return 2 * i + 2; }
 
    static int kThGreatest(Heap h, int k)
    {
        PriorityQueue<Map.Entry<Integer, Integer> > p
            = new PriorityQueue<>(
                (a, b) -> b.getKey() - a.getKey());
        p.add(Map.entry(h.v.get(0), 0));
 
        for (int i = 0; i < k - 1; ++i) {
            int j = p.peek().getValue();
            p.remove();
            int l = left(j), r = right(j);
            if (l < h.n)
                p.add(Map.entry(h.v.get(l), l));
            if (r < h.n)
                p.add(Map.entry(h.v.get(r), r));
        }
        return p.peek().getKey();
    }
 
    // Driver Code
    public static void main(String[] args)
    {
        Heap h = new Heap(7);
        h.v = new ArrayList<>(
            Arrays.asList(20, 15, 18, 8, 10, 5, 17));
        int k = 2;
 
        System.out.println(kThGreatest(h, k));
    }
}


Python




import heapq
 
# Structure for the heap
class Heap:
    def __init__(self, arr):
        self.v = arr
        self.n = len(arr)
 
# Returns the index of the left child node
def left(i):
    return 2 * i + 1
 
# Returns the index of the right child node
def right(i):
    return 2 * i + 2
 
def k_th_greatest(h, k):
    p = [(-h.v[0], 0)]
    heapq.heapify(p)
 
    for i in range(k - 1):
        val, j = heapq.heappop(p)
        l, r = left(j), right(j)
        if l < h.n:
            heapq.heappush(p, (-h.v[l], l))
        if r < h.n:
            heapq.heappush(p, (-h.v[r], r))
 
    return -p[0][0]
 
# Driver Code
if __name__ == "__main__":
    h = Heap([20, 15, 18, 8, 10, 5, 17])
    k = 2
 
    print(k_th_greatest(h, k))


C#




using System;
using System.Collections.Generic;
 
class MainClass {
    // Structure for the heap
    class Heap {
        public List<int> v;
        public int n; // Size of the heap
 
        public Heap(int i = 0) {
            n = i;
            v = new List<int>(n);
        }
    }
 
    // Returns the index of the left child node
    static int Left(int i) { return 2 * i + 1; }
 
    // Returns the index of the right child node
    static int Right(int i) { return 2 * i + 2; }
 
    static int KthGreatest(Heap h, int k) {
        PriorityQueue<Tuple<int, int>> p =
          new PriorityQueue<Tuple<int, int>>(Comparer<Tuple<int, int>>.Create((t1, t2) => t2.Item1.CompareTo(t1.Item1)));
        p.Enqueue(Tuple.Create(h.v[0], 0));
 
        for (int i = 0; i < k - 1; ++i) {
            Tuple<int, int> tuple = p.Dequeue();
            int j = tuple.Item2;
            int l = Left(j), r = Right(j);
            if (l < h.n)
                p.Enqueue(Tuple.Create(h.v[l], l));
            if (r < h.n)
                p.Enqueue(Tuple.Create(h.v[r], r));
        }
        return p.Peek().Item1;
    }
 
    public static void Main(string[] args) {
        Heap h = new Heap(7);
        h.v = new List<int> { 20, 15, 18, 8, 10, 5, 17 };
        int k = 2;
 
        Console.WriteLine(KthGreatest(h, k));
    }
 
    // PriorityQueue implementation in C#
    class PriorityQueue<T> {
        private List<T> data;
        private IComparer<T> comparer;
 
        public PriorityQueue(IComparer<T> comparer = null) {
            this.data = new List<T>();
            this.comparer = comparer ?? Comparer<T>.Default;
        }
 
        public void Enqueue(T item) {
            data.Add(item);
            int childIndex = data.Count - 1;
            while (childIndex > 0) {
                int parentIndex = (childIndex - 1) / 2;
                if (comparer.Compare(data[childIndex], data[parentIndex]) >= 0) {
                    break;
                }
                Swap(childIndex, parentIndex);
                childIndex = parentIndex;
            }
        }
 
        public T Dequeue() {
            int lastIndex = data.Count - 1;
            T frontItem = data[0];
            data[0] = data[lastIndex];
            data.RemoveAt(lastIndex);
 
            --lastIndex;
            int parentIndex = 0;
            while (true) {
                int leftChild = parentIndex * 2 + 1;
                if (leftChild > lastIndex) {
                    break;
                }
                int rightChild = leftChild + 1;
                if (rightChild <= lastIndex &&
                    comparer.Compare(data[rightChild], data[leftChild]) < 0) {
                    leftChild = rightChild;
                }
                if (comparer.Compare(data[parentIndex], data[leftChild]) <= 0) {
                    break;
                }
                Swap(parentIndex, leftChild);
                parentIndex = leftChild;
            }
            return frontItem;
        }
 
        public T Peek() {
            T frontItem = data[0];
            return frontItem;
        }
 
        public int Count() {
            return data.Count;
        }
 
        private void Swap(int index1, int index2) {
            T temp = data[index1];
            data[index1] = data[index2];
            data[index2] = temp;
        }
    }
}
 
// This code is contributed by shivamgupta0987654321


Javascript




class Heap {
    constructor(i = 0) {
        this.n = i;
        this.v = new Array(i);
    }
}
 
// Returns the index of the left child node
function left(i) {
    return 2 * i + 1;
}
 
// Returns the index of the right child node
function right(i) {
    return 2 * i + 2;
}
 
function kThGreatest(h, k) {
    const p = new PriorityQueue((a, b) => b[0] - a[0]);
    p.enqueue([-h.v[0], 0]);
 
    for (let i = 0; i < k - 1; ++i) {
        const [val, j] = p.dequeue();
        const l = left(j), r = right(j);
        if (l < h.n)
            p.enqueue([-h.v[l], l]);
        if (r < h.n)
            p.enqueue([-h.v[r], r]);
    }
 
    return -p.peek()[0];
}
 
// Driver Code
function main() {
    const h = new Heap(7);
    h.v = [20, 15, 18, 8, 10, 5, 17];
    const k = 2;
 
    console.log(kThGreatest(h, k));
}
 
// PriorityQueue class for JavaScript
class PriorityQueue {
    constructor(comparator) {
        this.data = [];
        this.comparator = comparator || ((a, b) => a - b);
    }
 
    enqueue(item) {
        this.data.push(item);
        this.bubbleUp();
    }
 
    dequeue() {
        const root = this.data[0];
        const last = this.data.pop();
        if (this.data.length > 0) {
            this.data[0] = last;
            this.bubbleDown();
        }
        return root;
    }
 
    peek() {
        return this.data[0];
    }
 
    get length() {
        return this.data.length;
    }
 
    bubbleUp() {
        let i = this.data.length - 1;
        while (i > 0) {
            const j = Math.floor((i - 1) / 2);
            if (this.comparator(this.data[i][0], this.data[j][0]) >= 0) {
                break;
            }
            [this.data[i], this.data[j]] = [this.data[j], this.data[i]];
            i = j;
        }
    }
 
    bubbleDown() {
        let i = 0;
        while (true) {
            const left = 2 * i + 1;
            const right = 2 * i + 2;
            let smallest = i;
 
            if (left < this.data.length && this.comparator(this.data[left][0], this.data[smallest][0]) < 0) {
                smallest = left;
            }
 
            if (right < this.data.length && this.comparator(this.data[right][0], this.data[smallest][0]) < 0) {
                smallest = right;
            }
 
            if (smallest === i) {
                break;
            }
 
            [this.data[i], this.data[smallest]] = [this.data[smallest], this.data[i]];
            i = smallest;
        }
    }
}
 
// Run the program
main();


Output

18




Complexity Analysis:

  • Time Complexity: O(N * log k)
  • Auxiliary Space: O(n)

For each element, we insert the element in the heap and remove if the heap size is greater than k. So precisely 1 heapify operation will be required for the initial k elements and after that 2 heapify operations will be required for the rest of the elements. This makes time complexity O(N*logK)



Last Updated : 16 Feb, 2024
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads