# Priority queue

An ordinary queue is a first in first out data structure. Elements are added at the end of the queue and deleted from the queue head. In some cases, we may need to find the maximum or minimum value in the queue. For example, a queue is used to save computer tasks. Generally, computer tasks have priority. We need to find the task with the highest priority among these computer tasks to execute first. After execution, we need to remove this task from the queue. To complete this function, ordinary queues need to traverse all elements in the queue every time, compare and find the maximum value. The efficiency is not very high. At this time, we can use a special queue to complete this demand, priority queue.

According to their different functions, priority queues can be divided into the following two types:

1. Maximum priority queue: you can get and delete the maximum value in the queue
2. Minimum priority queue: the smallest value in the queue can be obtained and deleted

# 1 maximum priority queue

We have learned about heap before, and the heap structure can easily delete the maximum value. Therefore, next, we can realize the maximum priority queue based on the heap area.

## 1.2 code implementation of maximum priority queue

```/**
* Maximum priority queue
* Implementation with heap
*/
public class MaxPriorityQueue<T extends Comparable<T>> {
//Define an array to store elements in the heap
private T[] items;
//Number of elements in the storage heap
private int N;

//Constructor initialization parameters
public MaxPriorityQueue(int capacity) {
items = (T[]) new Comparable[capacity + 1];
this.N = 0;
}

//Number of elements in the queue
public int size() {
return N;
}

//Is the queue empty
public boolean isEmpty() {
return N == 0;
}

//Queue insert element
public void insert(T t) {
//Add elements at the maximum index and increment
items[++N] = t;
//Float the element up to the correct position
swim(N);
}

//The queue floats up after the element is inserted so that it is in the correct position
public void swim(int k) {
while (k > 1) {
if (less(k / 2, k)) {
exch(k / 2, k);
}
k = k / 2;
}
}

//Delete the largest element and return this element
public T delMax() {
T max = items[1];
//Swap the position of the largest element and the last element
exch(1, N);
//Delete last element
items[N] = null;
N--;
//Sink element 1 to the correct position
sink(1);
return max;
}

//Sink after deleting elements
public void sink(int k) {
while (2 * k <= N) {
int max;
//If there are right child nodes
if (2 * k + 1 <= N) {
if (less(2 * k + 1, 2 * k)) {
max = 2 * k;
} else {
max = 2 * k + 1;
}
} else {
max = 2 * k;
}

if (!less(k, max)) {
break;
}
exch(k, max);
k = max;
}
}

//Compare element sizes
public boolean less(int i, int j) {
return items[i].compareTo(items[j]) < 0;
}

//Exchange element
public void exch(int i, int j) {
T temp = items[i];
items[i] = items[j];
items[j] = temp;
}

public static void main(String[] args) {
//Create minimum priority queue object
MaxPriorityQueue<String> queue = new MaxPriorityQueue<>(10);
//Save data to queue
queue.insert("G");
queue.insert("F");
queue.insert("E");
queue.insert("D");
queue.insert("C");
queue.insert("B");
queue.insert("A");

//Get the elements in the minimum priority queue through a loop
while (!queue.isEmpty()) {
String min = queue.delMax();
System.out.print(min + " ");
}

}
}
```

# 2 minimum priority queue

The implementation of the minimum priority queue is also relatively simple. We can also complete the minimum priority queue based on the heap. When we studied the heap earlier, the arrays storing data elements in the heap should meet the following characteristics:

1. The largest element is placed at index 1 of the array.
2. The data of each node is always greater than or equal to the data of its two child nodes.

In fact, the heap we implemented before can be called the maximum heap. We can use the opposite idea to realize the minimum heap, so that the array storing data elements in the heap meets the following characteristics:

1. The smallest element is placed at index 1 of the array.
2. The data of each node is always less than or equal to the data of its two child nodes.
3. In this way, we can quickly access the smallest data in the heap.

## 2.2 code implementation of minimum priority queue

```/**
* Minimum priority queue
* Implementation with heap
*/
public class MinPriorityQueue<T extends Comparable<T>> {

//Define an array to store elements in the heap
private T[] items;
//Record the number of elements in the heap
private int N;

//Constructor initialization parameters
public MinPriorityQueue(int capacity) {
items = (T[]) new Comparable[capacity + 1];
this.N = 0;
}

//Judge whether the queue is empty
public boolean isEmpty() {
return N == 0;
}

//Get the number of elements in the queue
public int size() {
return N;
}

//Insert elements (insert elements at the maximum index and float up to adjust the order)
public void insert(T t) {
items[++N] = t;
//Float up
swim(N);
}

//Floating up operation after inserting an element, so that the inserted k element is in another correct position in the heap
public void swim(int k) {
//Comparison between k and its parent node k/2
while (k > 1) {
if (less(k, k / 2)) {
exch(k, k / 2);
}
k = k / 2;
}
}

//Delete maximum element
public T delMin() {
//Take out the largest element with index 1
T minT = items[1];
//Swap maximum index and 1 element
exch(1, N);
//Delete element at maximum index
items[N] = null;
//Element decrement
N--;
//Now drop the element with index 1 and adjust it to the correct position
sink(1);
return minT;
}

//Sink after deleting the largest element (the last element is exchanged with the first element)
public void sink(int k) {
while (2 * k <= N) {
//Find the maximum value in the child node
//If there is a right child node
int min;
if (2 * k + 1 <= N) {
if (less(2 * k, 2 * k + 1)) {
min = 2 * k;
} else {
min = 2 * k + 1;
}
} else {
min = 2 * k;
}

//Interpret the current node and child node values
if (less(k, min)) {
break;
}
exch(k, min);
//The index points to the child node
k = min;
}
}

//Compare element sizes
public boolean less(int i, int j) {
return items[i].compareTo(items[j]) < 0;
}

//Swap element location
public void exch(int i, int j) {
T temp = items[i];
items[i] = items[j];
items[j] = temp;
}

public static void main(String[] args) {
//Create minimum priority queue object
MinPriorityQueue<String> queue = new MinPriorityQueue<>(10);
//Save data to queue
queue.insert("G");
queue.insert("F");
queue.insert("E");
queue.insert("D");
queue.insert("C");
queue.insert("B");
queue.insert("A");

//Get the elements in the minimum priority queue through a loop
while (!queue.isEmpty()) {
String min = queue.delMin();
System.out.print(min + " ");
}

}
}

```

# 3 index priority queue

In the previously implemented maximum priority queue and minimum priority queue, they can quickly access the maximum and minimum elements in the queue respectively, but they have a disadvantage that they have no way to access the objects that already exist in the priority queue through the index and update them. In order to achieve this goal, based on the priority queue, learn a new data structure, index the priority queue. Next, we take the minimum index priority queue as an example.

## 3.1 implementation idea of index priority queue

Step 1:

When storing data, associate each data element with an integer, such as insert (int, k, t, t). We can regard k as an integer associated with T. then our implementation needs to quickly obtain the T element in the queue through the value of k. at this time, the value of k needs to be unique.
The most intuitive idea is that we can use a T[] items array to save data elements. When inserting (int k, t t t), we can regard K as the index of the items array and put the T element at the index k of the items array. In this way, it is very convenient for us to obtain the T element according to K, and we can get the items[k] directly.

Step 2:

As a result of the completion of step 1, although we associate an integer with each element and can use this integer to quickly obtain the element, the order of the elements in the items array is random and not heap ordered. Therefore, in order to meet this requirement, we can add an array int[]pq to save the index of each element in the items array, The PQ array needs to be heap ordered, that is, the data elements items[pq[1]] corresponding to pq[1] should be less than or equal to the data elements items[pq[2]] and items[pq[3]] corresponding to pq[2] and pq[3].

Three steps:

Through the analysis in step 2, we can find that when we make heap adjustment through floating and sinking, we actually adjust the pq array. If you need to modify the elements in items, such as making items[0] = "H", it is obvious that we need to adjust the heap of the data in pq, and adjust the position of the elements in pq[9]. But now we will encounter a problem. What we modify is the value at the 0 index in the items array. How can we quickly know the position of the element in pq[9]? The most intuitive idea is to traverse the pq array and compare each element with 0. If the current element is 0, then adjust the element at the index, but the efficiency is very low. We can add another array, int[] qp, to store the reverse order of pq. For example: in pq array: pq[1]=6; Then, in the qp array, take 6 as the index and 1 as the value, and the result is: qp[6]=1;

After having pq array, if we modify items[0] = "H", we can first find the index of qp in qp array through index 0: qp[0]=9, and then adjust pq[9] directly.

## 3.3 code implementation of minimum index priority queue

```/**
* Minimum index priority queue
*/
public class IndexMinPriorityQueue<T extends Comparable<T>> {
//Elements in the storage heap
private T[] items;
//Save the index of each element in the items array. The pq array needs to be heap ordered
private int[] pq;
//Save the reverse order of pq, with pq value as index and pq index as value
private int[] qp;
//Record the number of elements in the heap
private int N;

//Constructor
public IndexMinPriorityQueue(int capacity) {
items = (T[]) new Comparable[capacity + 1];
pq = new int[capacity + 1];
qp = new int[capacity + 1];
this.N = 0;

//The default queue does not store elements
for (int i = 0; i < qp.length; i++) {
qp[i] = -1;
}
}

//Is the queue empty
public boolean isEmpty() {
return N == 0;
}

//Queue size
public int size() {
return N;
}

//Compare size
public boolean less(int i, int j) {
//Element size at pq index
return items[pq[i]].compareTo(items[pq[j]]) < 0;
}

//Exchange element order
public void exch(int i, int j) {
//Index order in exchange pq
int temp = pq[i];
pq[i] = pq[j];
pq[j] = temp;

//Update data in qp
qp[pq[i]] = i;
qp[pq[j]] = j;
}

//Judge whether the index at k already exists
public boolean contain(int k) {
return qp[k] != -1;
}

//Index associated with the smallest element
public int minIndex() {
return pq[1];
}

//Insert element t at index i
public void insert(int i, T t) {
if (contain(i)) {
return;
}
//Save the data to the i position corresponding to the items
items[i] = t;
//Number of elements plus 1
N++;
//Store i in pq
pq[N] = i;
//Reverse order in record qp
qp[i] = N;
//Complete reactor adjustment by floating up
swim(i);
}

//Delete minimum index
public int delMin() {
//Gets the index associated with the smallest element
int minIndex = pq[1];
//Swap elements at 1 and N at pq index
exch(1, N);
//Delete inverse index
qp[pq[N]] = -1;
//Delete index stored in pq
pq[N] = -1;
//Delete element
items[minIndex] = null;
N--;
//Sinking operation
sink(1);
return minIndex;
}

//Deletes the specified index
public void delete(int i) {
//i index at pq
int k = qp[i];
//Swap k and last element index
exch(k, N);
//Delete element
items[k] = null;
//Delete inverse index
qp[pq[N]] = -1;
//Delete the index
pq[N] = -1;
sink(k);
swim(k);
}

//Change the element associated with index i to t
public void changeItem(int i, T t) {
//Modify the element at i position in the items array to t
int k = qp[i];
//Find where i appears in pq
items[k] = t;
swim(k);
sink(k);
}

//Float up
public void swim(int k) {
while (k > 1) {
if (less(k, k / 2)) {
exch(k, k / 2);
}
k = k / 2;
}
}

//sink
public void sink(int k) {
while (2 * k < N) {
//Find the smallest element index in the child node
int min;
//If there are right child nodes
if (2 * k + 1 < N) {
if (less(2 * k + 1, 2 * k)) {
min = 2 * k + 1;
} else {
min = 2 * k;
}
} else {
min = 2 * k;
}
//If it is larger than the child node, no swap is needed
if (!less(k, min)) {
break;
}
exch(k, min);
k = min;
}
}

public static void main(String[] args) {
//Create index minimum priority queue object
IndexMinPriorityQueue<String> queue = new IndexMinPriorityQueue<>(10);

queue.insert(0, "A");
queue.insert(1, "C");
queue.insert(2, "F");

//Test modification
queue.changeItem(2, "B");

//Test delete
while (!queue.isEmpty()) {
int index = queue.delMin();
System.out.print(index + " ");
}
}
}

```

## 3.4 implementation of maximum index priority queue

```package com.bcl.algorithm.priority;

/**
* Index maximum priority queue
*/
public class IndexMaxPriorityQueue<T extends Comparable<T>> {
//Elements in the storage heap
private T[] items;
//Store items index value
private int[] pq;
//Store the reverse order of the indexes in pq. The value of pq is the index and the index is the value
private int[] qp;
//Storing data in heap
private int N;

//Constructor initialization parameters
public IndexMaxPriorityQueue(int capacity) {
items = (T[]) new Comparable[capacity + 1];
pq = new int[capacity + 1];
qp = new int[capacity + 1];
this.N = 0;

//        for (int i : qp) {
//            qp[i] = -1;
//        }
//The default queue does not store elements
for (int i = 0; i < qp.length; i++) {
qp[i] = -1;
}
}

//Is the queue empty
public boolean isEmpty() {
return N == 0;
}

//Queue size
public int size() {
return N;
}

public boolean max(int i, int j) {
return items[pq[i]].compareTo(items[pq[j]]) > 0;
}

//Exchange element order
public void exch(int i, int j) {
//Index order in exchange pq
int temp = pq[i];
pq[i] = pq[j];
pq[j] = temp;

//Update data in qp
qp[pq[i]] = i;
qp[pq[j]] = j;
}

//Include corresponding index
public boolean contain(int i) {
return qp[i] != -1;
}

//Maximum index
public int maxIndex() {
return pq[1];
}

//Insert element at index i
public void insert(int i, T t) {
if (contain(i)) {
return;
}
//Insert element t at items
items[i] = t;
//Self increasing number
N++;
pq[N] = i;
//qp increases in reverse order
qp[i] = N;
//Float up and adjust the reactor sequence
swim(N);
}

//Delete maximum index
public int delMaxIndex() {
//Maximum element index found
int maxIndex = pq[1];
//Exchange element
exch(1, N);
//Delete element
items[maxIndex] = null;
//Delete inverse index
qp[pq[N]] = -1;
//Delete index
pq[N] = -1;
//Element reduction
N--;
sink(1);
return maxIndex;
}

//Delete element at index i
public void delete(int i) {
//Find the position of index i in pq and adjust the order of pq
int k = qp[i];
//Swap element positions at k
exch(k, N);
//Delete element
items[k] = null;
qp[pq[N]] = -1;
//Delete elements in pq
pq[N] = -1;
sink(k);
swim(k);
}

//Modify the value at index i to t
public void changeItems(int i, T t) {
items[i] = t;
int k = qp[i];
swim(k);
sink(k);
}

public void swim(int k) {
while (k > 1) {
if (max(k, k / 2)) {
exch(k, k / 2);
}
k = k / 2;
}
}

//Adjust the stacking sequence by sinking
public void sink(int k) {
while (2 * k <= N) {
//Maximum child node found
int max;
if (2 * k + 1 <= N) {
if (max(2 * k + 1, 2 * k)) {
max = 2 * k + 1;
} else {
max = 2 * k;
}
} else {
max = 2 * k;
}
if (max(k, max)) {
break;
}
exch(k, max);
k = max;
}
}

public static void main(String[] args) {
//Create index minimum priority queue object
IndexMaxPriorityQueue<String> queue = new IndexMaxPriorityQueue<>(10);

queue.insert(0, "A");
queue.insert(1, "C");
queue.insert(2, "F");

//Test modification
queue.changeItems(2, "B");

//Test delete
while (!queue.isEmpty()) {
int index = queue.delMaxIndex();
System.out.print(index + " ");
}
}
}

```

Keywords: Algorithm

Added by Vivid Lust on Mon, 07 Feb 2022 15:01:59 +0200