Detailed explanation of common usage of [c + + container] priority_queue

Posted by jvquach on Fri, 17 Dec 2021 00:56:31 +0100

priority_queue is also called priority queue, and its bottom layer is implemented by heap. In the priority queue, the first element must be when

The highest priority in the previous queue. For example, there are the following elements in the queue, and the priority is defined:

Peach(Priority 3)
 
Pear(Priority 4)
 
Apple(Priority 1)

Then the order of leaving the team is pear (4) → peach (3) → apple (1).

Of course, you can add (push) elements to the priority queue at any time, and the underlying data structure heap of the priority queue will follow

Adjust the structure so that each team head element has the highest priority.

The priority here is specified. For example, in the above example, it can also be specified that the smaller the number, the greater the priority.

To use the priority queue, first add the header file #include < queue > and add "using namespace" under the header file

std;".

1.priority_ Definition of queue

The definition is written in the same way as other STL containers. typename can be any basic data type or container:

priority_queue<typename> name;

2.priority_ Access to elements in the queue container

Unlike the queue, the priority queue has no front() function and back() function, but can only access the first element of the queue through the top() function

Element (also known as heap top element), that is, the element with the highest priority.

Program code:

#include<cstdio> 
#include<queue>
using namespace std;
int main(int argc,char** argv) {
	priority_queue<int> q;
	q.push(3);
	q.push(4);
	q.push(1);
	printf("%d\n",q.top());
	return 0; 
}

Operation results:

As shown above, the team head element has the highest priority, and the team head element is 4.

3.priority_ Analysis of common function instances of queue

(1)push()
push(x) will queue x with a time complexity of O(logN), where N is the number of elements in the current priority queue. See "priority" for an example

Access to elements in the queue container.

(2)top()
top() can obtain the first element of the queue (i.e. the top element of the heap), and the time complexity is O(1). For an example, see "priority_queue" for the description of the elements in the container

Ask.

Before using the top() function, you must use empty() to determine whether the priority queue is empty.

(3)pop()
pop() can dequeue the first element (i.e. the top element) with a time complexity of O(logN).

Before using the pop() function, you must use empty() to determine whether the priority queue is empty.

Program code:

#include<cstdio> 
#include<queue>
using namespace std;
int main() {
	priority_queue<int> q;
	q.push(3);
	q.push(4);
	q.push(1);
	printf("%d\n",q.top());
	q.pop(); 
	printf("%d\n",q.top());
	return 0; 
}

(4)empty()

empty() checks whether the priority queue is empty. If it is empty, it returns true. If it is not empty, it returns false. The time complexity is O(1).

Program code:

 

#include<cstdio> 
#include<queue>
using namespace std;
int main(){
	priority_queue<int> q;
	printf("%d\n",q.empty());	//If there is no element at the beginning, it is empty (true); Output 1
	q.push(3);
	printf("%d\n",q.empty());	//Press in the element, which is not visible (false); Output 0
	return 0; 
}

 (5)size()

size() returns the number of elements in the priority queue, with time complexity O(1).

Program code:

#include<cstdio> 
#include<queue>
using namespace std;
int main(){
	priority_queue<int> q;
	for(int i=0;i<=3;i++) {
		q.push(i);
	}
	printf("%d\n",(int)q.size());	//Number of output queue elements 
	return 0; 
}

 

4. priority_ Setting of element priority in queue

How to define the priority of the elements in the priority queue is the key to make good use of the priority queue

(1) Priority setting of basic data type

The basic data types referred to here are the data types that can be used directly, such as int, double, char, etc. the priority queue is responsible for it

The priority setting of the priority is generally the higher the number, so the first element of the queue is the one with the largest element in the priority queue (if any)

char type, the largest dictionary order). For basic data types, the definitions of the following two priority queues are equivalent (int type is preferred)

For example, notice that there is a space between the last two >:

priority_queue<int> q;
priority_queue<int, vector<int>, less<int> > q;
priority_queue<double, vector<double>, greater<double> > q;

In the latter two definitions, there are two more parameters, vector < > and less < > (greater < >).

The second parameter vector < > is the container used to host the underlying data structure heap;

The third parameter less < > or greater < > is a comparison class for the first parameter. Less < int > means that the greater the number, the greater the priority,

Greater < int > indicates that the smaller the number, the higher the priority.

Program code:

#include<cstdio>
#include<queue>
using namespace std;
int main(){
	priority_queue<int,vector<int>, greater<int> > q;
	q.push(3);
	q.push(1);
	q.push(4);
	printf("%d\n",q.top());	 
	return 0; 
}

Normally, the team head element should be the largest element 4, but greater < int > means that the smaller the number, the higher the priority, and the result is 1.

In fact, basic data types can also use the priority setting method of structures.

(2) Priority setting of structure

Create a structure and reload the less than sign "<":

struct fruit {
	string name;
	int price;
	//Overload less than sign
	friend bool operator < (fruit f1, fruit f2)  {
		return f1.price<f2.price;
	}
};

Define priority queue:

priority_queue<fruit> q;

Overloading is to redefine the existing operators and add a function to the fruit structure, where "friend" is a friend; hinder

"Bool operator < (fruit F1, fruit F2)" overloads the operator "<" of fruit type; The internal of the function is "return"

f1. price<f2. price;”, Therefore, the function of less than sign or less than sign after overloading. At this point, you can directly define the priority team of fruit type

Column, which takes the fruit with high price as the priority. If you want to give priority to the fruit with low price, you only need to

Change the less than sign in return to the greater than sign.

Program code:

#include<iostream> 
#include<queue>
#include<string>
using namespace std;
struct fruit {
	string name;
	int price;
	//Overload is less than the number, and the priority of high price is high 
	friend bool operator < (fruit f1, fruit f2)  {
		return f1.price<f2.price;
	}
}f1,f2,f3;
int main(){
	priority_queue<fruit> q;
	f1.name = "Peach";
	f1.price = 3;
	f2.name = "Pear";
	f2.price = 4;
	f3.name = "Apple";
	f3.price = 1;
	q.push(f1);
	q.push(f2);
	q.push(f3);
	cout << q.top().name << " " << q.top().price << endl;
	return 0; 
}

be careful:

Overloading the greater than sign will cause compilation errors, because mathematically, it only needs to overload the less than sign, that is, judging F1 > F2 is equivalent to judging F2 < F1, 2

f1==f2 is equivalent to judgment! (f1<f2)&&! (f2<f1). As shown below:

The overloading of the less than sign here is somewhat similar to the cmp function in the sort function. Their parameters are two variables, which are internal to the function

Both return true or false. In fact, the two functions are indeed similar, but the effect seems to be "similar"

"Anti". In sorting, if "return F1. Price > F2. Price" is selected, the sorting will be based on the price from high to low, but the sorting will take precedence

In the queue, the one with low price is put at the head of the team. The reason is that the default rule of the priority queue itself is to put the high priority at the head of the queue,

Therefore, reloading the less than sign to the greater than sign only reverses this rule. This function of the priority queue is the same as that in sort

The effect of cmp function is the opposite.

Of course, you can also write overloaded functions outside the structure:

struct cmp {
	bool operater () (fruit f1,fruit f2) {
		return f1.price > f2.price;
	}
}; 

Define priority queue:

priority_queue<fruit,vector<fruit>,cmp> q;

Program code:

#include<iostream> 
#include<queue>
#include<string>
using namespace std;
struct fruit {
	string name;
	int price;
}f1,f2,f3;
struct cmp {
	bool operator () (fruit f1, fruit f2) {
		return f1.price < f2.price;
	}
}; 
int main(){
	priority_queue<fruit,vector<fruit>,cmp> q;
	f1.name = "Peach";
	f1.price = 3;
	f2.name = "Pear";
	f2.price = 4;
	f3.name = "Apple";
	f3.price = 1;
	q.push(f1);
	q.push(f2);
	q.push(f3);
	cout << q.top().name << " " << q.top().price << endl;
	return 0; 
}

Similarly, even basic data types or other STL containers, such as (set), can define priorities in the same way

Finally, it is pointed out that if the data in the structure is huge, such as strings or arrays, it is recommended to use references to improve efficiency. Comparison at this time

"const" and "&" should be added to the parameters of class, as shown below:

friend bool operator < (const fruit &f1, const fruit &f2) {
		return f1.price < f2.price;
}
bool operator () (const fruit &f1, const fruit &f2) {
		return f1.price < f2.price;
}

Reprint: https://blog.csdn.net/qq_42410605/article/details/100537452?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163063047716780366530718%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=163063047716780366530718&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_v2~rank_v29-2-100537452.pc_search_result_cache&utm_term=priority_queue&spm=1018.2226.3001.4187

Topics: C++ STL