Play Data Structure (15) -- heap-based priority queue

Heap-based priority queue

I. Code Implementation

Queue.java

public interface Queue<E> {

    int getSize();
    boolean isEmpty();
    void enqueue(E e);
    E dequeue();
    E getFront();
}

PriorityQueue.java

public class PriorityQueue<E extends Comparable<E>> implements Queue<E> {

    private MaxHeap<E> maxHeap;

    public PriorityQueue(){
        maxHeap = new MaxHeap<>();
    }

    @Override
    public int getSize(){
        return maxHeap.size();
    }

    @Override
    public boolean isEmpty(){
        return maxHeap.isEmpty();
    }

    @Override
    public E getFront(){	//Look at the team leader element
        return maxHeap.findMax();
    }

    @Override
    public void enqueue(E e){	//Entry operation, bring e element into the queue
        maxHeap.add(e);
    }

    @Override
    public E dequeue(){//Out-of-line operation (head element, extract maximum)
        return maxHeap.extractMax();
    }
}

Classical Questions of Priority Queue

Choose the first 100 elements from 100,000 elements [the first M elements from N elements, M < N]

Solution:

1. The time complexity of using advanced sorting (merging, etc.) is NlogN.

2. The time complexity of using priority queue is NlogM; (M < N)

The idea of using priority queue method: [using minimum heap]

Maintain the first M elements currently seen with the priority queue, put the first M elements of N elements into the priority queue, and then replace the smallest element in the priority queue with a new element whenever a new element is seen, if the new element is larger than the smallest element in the priority queue; until traversal. When all N elements are finished, the M elements left in them are the M elements we are looking for.

Specific issues:

Topic Links

Code implementation:

Solution.java

import java.util.LinkedList;
import java.util.List;
import java.util.TreeMap;

class Solution {

    private class Array<E> {

        private E[] data;
        private int size;

        // Constructor, capacity capacity of the incoming array constructs Array
        public Array(int capacity){
            data = (E[])new Object[capacity];
            size = 0;
        }

        // No parameter constructor, default array capacity=10
        public Array(){
            this(10);
        }

        public Array(E[] arr){
            data = (E[])new Object[arr.length];
            for(int i = 0 ; i < arr.length ; i ++)
                data[i] = arr[i];
            size = arr.length;
        }
}

        // Capture the capacity of an array
        public int getCapacity(){
            return data.length;
        }

        // Gets the number of elements in an array
        public int getSize(){
            return size;
        }

        // Whether the return array is empty
        public boolean isEmpty(){
            return size == 0;
        }

        // Insert a new element e at the index location
        public void add(int index, E e){

            if(index < 0 || index > size)
                throw new IllegalArgumentException("Add failed. Require index >= 0 and index <= size.");

            if(size == data.length)
                resize(2 * data.length);

            for(int i = size - 1; i >= index ; i --)
                data[i + 1] = data[i];

            data[index] = e;

            size ++;
        }

        // Add a new element to all elements
        public void addLast(E e){
            add(size, e);
        }

        // Add a new element before all elements
        public void addFirst(E e){
            add(0, e);
        }

        // Get the element of index index index location
        public E get(int index){
            if(index < 0 || index >= size)
                throw new IllegalArgumentException("Get failed. Index is illegal.");
            return data[index];
        }

        // Modify the index index location to e
        public void set(int index, E e){
            if(index < 0 || index >= size)
                throw new IllegalArgumentException("Set failed. Index is illegal.");
            data[index] = e;
        }

        // Find if there is an element e in the array
        public boolean contains(E e){
            for(int i = 0 ; i < size ; i ++){
                if(data[i].equals(e))
                    return true;
            }
            return false;
        }

        // Find the index of the element e in the array, and return - 1 if there is no element e
        public int find(E e){
            for(int i = 0 ; i < size ; i ++){
                if(data[i].equals(e))
                    return i;
            }
            return -1;
        }

        // Remove the element in the index position from the array and return the deleted element
        public E remove(int index){
            if(index < 0 || index >= size)
                throw new IllegalArgumentException("Remove failed. Index is illegal.");

            E ret = data[index];
            for(int i = index + 1 ; i < size ; i ++)
                data[i - 1] = data[i];
            size --;
            data[size] = null; // loitering objects != memory leak

            if(size == data.length / 4 && data.length / 2 != 0)
                resize(data.length / 2);
            return ret;
        }

        // Delete the first element from the array and return the deleted element
        public E removeFirst(){
            return remove(0);
        }

        // Delete the last element from the array and return the deleted element
        public E removeLast(){
            return remove(size - 1);
        }

        // Delete element e from the array
        public void removeElement(E e){
            int index = find(e);
            if(index != -1)
                remove(index);
        }

        public void swap(int i, int j){

            if(i < 0 || i >= size || j < 0 || j >= size)
                throw new IllegalArgumentException("Index is illegal.");

            E t = data[i];
            data[i] = data[j];
            data[j] = t;
        }

        @Override
        public String toString(){

            StringBuilder res = new StringBuilder();
            res.append(String.format("Array: size = %d , capacity = %d\n", size, data.length));
            res.append('[');
            for(int i = 0 ; i < size ; i ++){
                res.append(data[i]);
                if(i != size - 1)
                    res.append(", ");
            }
            res.append(']');
            return res.toString();
        }

        // Change the capacity of array space to the size of new Capacity
        private void resize(int newCapacity){

            E[] newData = (E[])new Object[newCapacity];
            for(int i = 0 ; i < size ; i ++)
                newData[i] = data[i];
            data = newData;
        }
    }

    private class MaxHeap<E extends Comparable<E>> {

        private Array<E> data;

        public MaxHeap(int capacity){
            data = new Array<>(capacity);
        }

        public MaxHeap(){
            data = new Array<>();
        }

        public MaxHeap(E[] arr){
            data = new Array<>(arr);
            for(int i = parent(arr.length - 1) ; i >= 0 ; i --)
                siftDown(i);
        }

        // Returns the number of elements in the heap
        public int size(){
            return data.getSize();
        }

        // Returns a Boolean value indicating whether the heap is empty
        public boolean isEmpty(){
            return data.isEmpty();
        }

        // Returns the index of the parent node of the element represented by an index in the array representation of a complete binary tree
        private int parent(int index){
            if(index == 0)
                throw new IllegalArgumentException("index-0 doesn't have parent.");
            return (index - 1) / 2;
        }

        // Returns the index of the left child node of the element represented by an index in the array representation of a complete binary tree
        private int leftChild(int index){
            return index * 2 + 1;
        }

        // Returns the index of the right child node of the element represented by an index in the array representation of a complete binary tree
        private int rightChild(int index){
            return index * 2 + 2;
        }

        // Adding elements to the heap
        public void add(E e){
            data.addLast(e);
            siftUp(data.getSize() - 1);
        }

        private void siftUp(int k){

            while(k > 0 && data.get(parent(k)).compareTo(data.get(k)) < 0 ){
                data.swap(k, parent(k));
                k = parent(k);
            }
        }

        // The largest element in the heap
        public E findMax(){
            if(data.getSize() == 0)
                throw new IllegalArgumentException("Can not findMax when heap is empty.");
            return data.get(0);
        }

        // Remove the largest element from the heap
        public E extractMax(){

            E ret = findMax();

            data.swap(0, data.getSize() - 1);
            data.removeLast();
            siftDown(0);

            return ret;
        }

        private void siftDown(int k){

            while(leftChild(k) < data.getSize()){
                int j = leftChild(k); // In this cycle, data[k] and data[j] exchange locations
                if( j + 1 < data.getSize() &&
                        data.get(j + 1).compareTo(data.get(j)) > 0 )
                    j ++;
                // data[j] is the maximum in leftChild and rightChild

                if(data.get(k).compareTo(data.get(j)) >= 0 )
                    break;

                data.swap(k, j);
                k = j;
            }
        }

        // Take out the largest element in the heap and replace it with element e
        public E replace(E e){

            E ret = findMax();
            data.set(0, e);
            siftDown(0);
            return ret;
        }
    }

    private interface Queue<E> {

        int getSize();
        boolean isEmpty();
        void enqueue(E e);
        E dequeue();
        E getFront();
    }

    private class PriorityQueue<E extends Comparable<E>> implements Queue<E> {

        private MaxHeap<E> maxHeap;

        public PriorityQueue(){
            maxHeap = new MaxHeap<>();
        }

        @Override
        public int getSize(){
            return maxHeap.size();
        }

        @Override
        public boolean isEmpty(){
            return maxHeap.isEmpty();
        }

        @Override
        public E getFront(){
            return maxHeap.findMax();
        }

        @Override
        public void enqueue(E e){
            maxHeap.add(e);
        }

        @Override
        public E dequeue(){
            return maxHeap.extractMax();
        }
    }

    private class Freq implements Comparable<Freq>{

        public int e, freq;

        public Freq(int e, int freq){
            this.e = e;
            this.freq = freq;
        }

        @Override
        public int compareTo(Freq another){
            if(this.freq < another.freq)
                return 1;
            else if(this.freq > another.freq)
                return -1;
            else
                return 0;
        }
    }

    public List<Integer> topKFrequent(int[] nums, int k) {	//Statistical frequency

        TreeMap<Integer, Integer> map = new TreeMap<>();
        for(int num: nums){
            if(map.containsKey(num))
                map.put(num, map.get(num) + 1);
            else
                map.put(num, 1);
        }

        PriorityQueue<Freq> pq = new PriorityQueue<>();//Using Priority Queue to Find the First K Elements
        for(int key: map.keySet()){
            if(pq.getSize() < k) 
                pq.enqueue(new Freq(key, map.get(key)));
            else if(map.get(key) > pq.getFront().freq){
                pq.dequeue();
                pq.enqueue(new Freq(key, map.get(key)));
            }
        }

        LinkedList<Integer> res = new LinkedList<>();
		//Put the elements in the priority queue back in LinkedList
        while(!pq.isEmpty())
            res.add(pq.dequeue().e);
        return res;
    }

Output success:

Method 2: Use the priority queue in the Java standard library

Code: Solution.java

import java.util.LinkedList;
import java.util.List;
import java.util.PriorityQueue;
import java.util.TreeMap;

public class Solution {

    private class Freq implements Comparable<Freq>{

        public int e, freq;

        public Freq(int e, int freq){
            this.e = e;
            this.freq = freq;
        }
 
        public int compareTo(Freq another){
            if(this.freq < another.freq)
                return -1;
            else if(this.freq > another.freq)
                return 1;
            else
                return 0;
        }
    }

    public List<Integer> topKFrequent(int[] nums, int k) {

        TreeMap<Integer, Integer> map = new TreeMap<>();
        for(int num: nums){
            if(map.containsKey(num))
                map.put(num, map.get(num) + 1);
            else
                map.put(num, 1);
        }

        PriorityQueue<Freq> pq = new PriorityQueue<>();
        for(int key: map.keySet()){
            if(pq.size() < k)
                pq.add(new Freq(key, map.get(key)));
            else if(map.get(key) > pq.peek().freq){
                pq.remove();
                pq.add(new Freq(key, map.get(key)));
            }
        }

        LinkedList<Integer> res = new LinkedList<>();
        while(!pq.isEmpty())
            res.add(pq.remove().e);
        return res;
    }
}

Supplement:

D-ary heap

2. Index heap: You can quickly know the location of an element in the heap by indexing and modify it.

3. Generalized Queue

Queues can be called as long as they support entry and exit operations.

Ordinary queue: FIFO, FIFO

Priority Queue: A queue with the highest priority element as the outgoing element [Stack can also be understood as a queue]

Keywords: Java

Added by Vince889 on Thu, 25 Jul 2019 12:23:06 +0300