First, the definition of binary heap
A heap tree is defined as follows:
(1) The heap must be a complete binary tree;
(2) The value of a node in the heap is always greater or less than the value of the child node;
(3) Each non-terminal node in the heap can be regarded as the root node of a heap.
The max heap is when the key value of the parent node is always greater than or equal to the key value of any child node. The min heap is when the key value of the parent node is always less than or equal to the key value of any child node. As shown in the figure below, the left is the max heap and the right is the min heap.
Second, the operation of the maximum heap
The original data is a[] = {4, 1, 3, 2, 16, 9, 10, 14, 8, 7}, which is stored sequentially, and the corresponding complete binary tree is shown in the following figure:
As an example of the binary tree in the above figure, let's construct a max heap:
First of all, the idea of constructing a maximum heap is: we do not need to traverse the maximum heap from the leaf node, because the leaf node has no child nodes, so the process of constructing a large heap for the leaf node is invalid, so we choose to start from the last leaf. The parent node of the node starts to construct the maximum heap from the bottom layer, and then goes up step by step, and finally forms a whole binary tree that is a maximum heap.
And the parent node of our last leaf node, its subscript position corresponding to the array is very special: (array length-1)/2, which is the element 16 in the above figure
In a complete binary tree, if the parent node position is i, then the left child is 2i+1, and the right child is 2i+2
So, we have to use 16 as the first root node and start building the maximum heap step by step!
The code is implemented as follows:
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); // build a large heap for (int i = parent(arr.length - 1); i >= 0; i--) siftDown (i); } // return the number of elements in the heap public int size() { return data.getSize(); } // Returns a boolean indicating if 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 the 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 of the element represented by an index in the array representation of the complete binary tree private int leftChild(int index) { return index * 2 + 1; } // Returns the index of the right child of the element represented by an index in the array representation of the complete binary tree private int rightChild(int index) { return index * 2 + 2; } // add element to heap public void add(E e) { data.addLast(e); // If the last element is large, it needs to float, because this is a large heap siftUp(data.getSize() - 1);// Float the last element up } private void siftUp(int i) { while (i > 0/* array has more than one element */ && data.get(parent(i)).compareTo(data.get(i)) < 0) { data.swap(i, parent(i)); i = parent(i); } } // look at 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); } // get the largest element from the heap public E extractMax() { E ret = findMax (); data.swap(0, data.getSize() - 1);// The first largest element and the last element are swapped data.removeLast(); siftDown(0);// sink the first element return ret; } private void siftDown(int k) { // precipitation while (leftChild(k) < data.getSize()) { int next = leftChild(k); if (next + 1 < data.getSize() && data.get(next + 1).compareTo(data.get(next)) > 0) { // we select the node on the right next++; } if (data.get(k).compareTo(data.get(next)) > 0) { // If the parent node is larger than the child node, it matches the large heap and exits directly break; } // otherwise select the left one data.swap(k, next); k = next; } } // Take 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; }
A max heap implementation has been done above! So, what about our priority queue? ?
Priority queue, as the name implies, is in a queue, not the principle of first-in, first-out, but to see what the priority of the added element is.
For example, I added 1, 2, 3 elements, at this time I added 4 elements (the priority criterion here is based on the size of the number), then the 4 at this time should replace the previous vertex (the previous one is 3), At this time, the head node is 4. At this time, our highest priority 4 is indeed moved to the top vertex.
Then, our priority queue can build a priority queue based on the max heap we have implemented above!
The code looks like this:
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() { return maxHeap.findMax(); } @Override public void enqueue(E e) { maxHeap.add(e); } @Override public E dequeue() { return maxHeap.extractMax(); } }