Priority queue - implementation based on max binary heap

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();
	}
}

  

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325108221&siteId=291194637