priority_queue
1. Introduction and use of priority_queue
1.1 Introduction to priority_queue
In C++, priority_queue is a container adapter that provides constant-time maximum element lookup. It is usually implemented as a heap. A heap is a data structure where the largest (or smallest) element is always at the top. priority_queue is a template class defined in the header file. It has three template parameters: element type, container type, and comparison function type (optional). By default it uses std::vector as its underlying container .
1.2 The use of priority_queue
Member functions:
1.2.1 constructor (construction)
int main ()
{
int myints[]= {
10,60,50,20};
priority_queue<int> q1;
priority_queue<int> q2(myints,myints+4);
priority_queue<int, vector<int>, greater<int>> q3(myints,myints+4);
return 0;
}
- q1 is empty.
- q2 contains four integers defined for , with 60 (the highest) on top of it.
- q3 has the same four integers, but since it uses instead of the default (ie ), it adds 10 as its top element for the new element. This new element is constructed in-place, passed as an argument to its constructor.
1.2.2 empty
In C++ STL, the empty() function is a predefined function used to check whether a collection is empty or not. Returns true (1) if the collection is empty, false (0) if the collection is not empty. The empty() function returns true for an empty container and false otherwise.
#include <iostream>
#include <queue>
using namespace std;
int main()
{
int a[] = {
3,6, 2,8,1 };
priority_queue<int> q1;
priority_queue<int> q2(a, a + 5);
cout << "q1:" << q1.empty() << endl;
cout << "q2:" << q2.empty() << endl;
return 0;
}
1.2.3 size
The size() function in C++ STL returns the number of elements in the container.
1.2.4 top
The top() function is a member function of the priority_queue class in C++ STL, which is used to return the reference of the first element in the priority queue. When using the top() function, you need to pay attention to whether the priority queue is empty, otherwise undefined behavior will occur.
int main()
{
int a[] = {
3,6, 2,8,1 };
priority_queue<int> q1;
priority_queue<int> q2(a, a + 5);
cout << "q1:" << q1.top() << endl;//报错
cout << "q2:" << q2.top() << endl;//8
return 0;
}
1.2.5 location
Construct and insert elements, add new elements. This new element is constructed in-place, passed as an argument to its constructor .
int main()
{
priority_queue<string> mypq;
mypq.emplace("orange");
mypq.emplace("strawberry");
mypq.emplace("apple");
mypq.emplace("pear");
cout << "mypq contains:";
while (!mypq.empty())
{
cout << ' ' << mypq.top();
mypq.pop();
}
cout << '\n';
return 0;
}
1.2.6 push、pop、swap
The push() function is used to insert new elements into the priority_queue and maintain the order of the queue.
The pop() function in priority_queue is used to remove the first element in the queue, which is the largest element.
The swap() function is used to exchange the elements of two priority_queues.
int main()
{
priority_queue<int> q1;
q1.push(1);
q1.push(2);
q1.push(3);
priority_queue<int> q2;
q2.push(4);
q2.push(5);
q2.push(6);
swap(q1, q2);
cout << "q1: ";
while (!q1.empty())
{
cout << q1.top() << ' ';
q1.pop();
}
cout << endl;
cout << "q2: ";
while (!q2.empty())
{
cout << q2.top() << ' ';
q2.pop();
}
cout << endl;
return 0;
}
1.3 The Kth largest element in the array
The Kth largest element in the array
The first method: Sort the array nums, and then find the kth largest number. It should be noted that the time complexity of general sorting in the algorithm is greater than O(N), that is, the counting sort is close to O(N).
The second method: create a priority queue with N elements, and find the k-th largest element, then delete the first k-1 elements in the priority queue, and the top of the last queue is the requested element
class Solution {
public:
int findKthLargest(vector<int>& nums, int k)
{
priority_queue<int> deq(nums.begin(), nums.end());
while(--k)
{
deq.pop();
}
return deq.top();
}
};
The third method: create a priority queue (small heap) with K elements, then traverse nums, enter the queue with large elements, and finally the top of the queue is the requested element
class Solution {
public:
int findKthLargest(vector<int>& nums, int k)
{
priority_queue<int, vector<int>, greater<int>> deq(nums.begin(), nums.begin() + k);
for (size_t i = k; i < nums.size(); ++i)
{
if (nums[i] > deq.top())
{
deq.pop();
deq.push(nums[i]);
}
}
return deq.top();
}
};
2. In-depth analysis and simulation implementation of priority_queue
priority_queue has three template parameters: element type, container type, and comparison function type (optional). By default, it uses std::vector as its underlying container , and does not require iterators, so the implementation is relatively simple.
namespace k
{
template<class T, class Container = vector<T>>
class priority_deque
{
public:
size_t size()
{
return _con.size();
}
void push(const T& x)
{
_con.push_back(x);
adjust_up(_con.size() - 1);
}
void pop()
{
swap(_con[0], _con[_con.size() - 1]);
_con.pop_back();
adjust_down(0);
}
const T& top()
{
return _con[0];
}
bool empty()
{
return _con.empty();
}
protected:
void adjust_up(size_t child)
{
size_t parent = (child - 1) / 2;
while (child > 0)
{
if (_con[parent] < _con[child])
{
swap(_con[child], _con[parent]);
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
void adjust_down(size_t parent)
{
size_t child = parent * 2 + 1;
while (child < _con.size())
{
if (child + 1 < _con.size() && _con[child] < _con[child + 1])
{
++child;
}
if (_con[parent] < _con[child])
{
swap(_con[child], _con[parent]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
private:
Container _con;
};
}
The above is the implementation of priority_queue, in which the upward adjustment (adjust_up) and downward adjustment (asjust_down) are adjusted to a large pile, which is hard-coded. If a small pile is required, how to do it? This is the detail of the template. As long as you define a comparison method, you can solve it.
namespace k
{
template<class T>
struct less
{
bool operator()(const T& x, const T& y)
{
return x < y;
}
};
template<class T>
struct greater
{
bool operator()(const T& x, const T& y)
{
return x > y;
}
};
template<class T, class Container = vector<T>, class Compare = less<T>>
class priority_deque
{
public:
size_t size()
{
return _con.size();
}
void push(const T& x)
{
_con.push_back(x);
adjust_up(_con.size() - 1);
}
void pop()
{
swap(_con[0], _con[_con.size() - 1]);
_con.pop_back();
adjust_down(0);
}
const T& top()
{
return _con[0];
}
bool empty()
{
return _con.empty();
}
protected:
void adjust_up(size_t child)
{
Compare com;
size_t parent = (child - 1) / 2;
while (child > 0)
{
if (com(_con[parent], _con[child]))
{
swap(_con[child], _con[parent]);
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
void adjust_down(size_t parent)
{
size_t child = parent * 2 + 1;
while (child < _con.size())
{
Compare com;
if (child + 1 < _con.size() && com(_con[child], _con[child + 1]))
{
++child;
}
if (com(_con[parent], _con[child]))
{
swap(_con[child], _con[parent]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
private:
Container _con;
};
}
Define two functors as above, and then template import can be implemented.