Skip to content
Advertisement

Java PriorityQueue: how to heapify a Collection with a custom Comparator?

For example, given a List of Integer List<Integer> list = Arrays.asList(5,4,5,2,2), how can I get a maxHeap from this List in O(n) time complexity?

The naive method:

PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Collections.reverseOrder());
for (Integer i : list) {
    maxHeap.offer(i);
}

However, the time complexity is O(nlogn).

We can trigger the heapify method by using the following constructor:

PriorityQueue<Integer> maxHeap = new PriorityQueue<>(list);

The time complexity is O(n). However, it forces me to use the natural order which is the minHeap.

My Question:

How can I construct a PriorityQueue by heapifying a Collection with custom Comparator?

Ref: Java doc of PriorityQueue

PS: @user207421
Heapify algorithm can transform any unsorted array into a heap in O(n) time, not O(nlogn). There are many articles about heapify, also in CLRS’s Introduction to Algorithms Page 159, build a heap from any unsorted array is O(n). And heap is also not a sorted array. It’s a complete tree with heap property which can be encoded in array.

Advertisement

Answer

If you don’t mind some hack

According to the java doc of PriorityQueue(PriorityQueue)

Creates a PriorityQueue containing the elements in the specified priority queue. This priority queue will be ordered according to the same ordering as the given priority queue.

So we can extend PriorityQueue as CustomComparatorPriorityQueue to hold the desired comparator and the Collection we need to heapify. Then call new PriorityQueue(PriorityQueue) with an instance of CustomComparatorPriorityQueue.

Below is tested to work in Java 15.

import java.util.*;

public class CustomComparatorPriorityQueue<T> extends PriorityQueue<T> {
    private Collection<T> wrapped;

    public static <U> PriorityQueue<U> create(Collection<U> wrapped, Comparator<U> custom) {
        return new PriorityQueue<U>(new CustomComparatorPriorityQueue<>(wrapped, custom));
    }

    private CustomComparatorPriorityQueue(Collection<T> wrapped, Comparator<T> custom) {
        super(custom);
        this.wrapped = wrapped;
    }

    @Override
    public Object[] toArray() {
        return wrapped.toArray();
    }

    public static void main(String[] args) {
        List<Integer> a = Arrays.asList(3, 6, 4, 8, 1, 9);
        PriorityQueue<Integer> pq = CustomComparatorPriorityQueue.create(a, Comparator.<Integer>naturalOrder().reversed());
        Integer b;
        while ((b = pq.poll()) != null) {
            System.out.println(b);
        }
    }

    // Override to don't allow other purpose...
}

User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement