注:本博文主要是为了记录STL中各数据结构的三个成员函数(压入、弹出、顶数据)的函数名,但像判空.empty()、长度.size()这些成员,在STL的所有数据结构中都使用了同样的名字,所以不再赘述。
数据结构 | 在STL中的名字 | 入 | 出 | 顶 | 删除 | 注 |
---|---|---|---|---|---|---|
最大堆 | priority_queue< Type > | Q.push() | Q.pop() | Q.top() | 只有Q.pop(),只能删除堆顶元素 | 虽然是一个queue,但队列头的返回方式不是Q.front(),而是Q.top(),取最大堆的“堆顶”之意。 |
双向链表 | deque< Type > | Q.push_front()、Q.push_back() | Q.pop_front()、Q.pop_back() | Q.front()、Q.back() | Q.erase(iter) | 由于其是双向链表,因此一切操作都有前(front)、后(back)两种。 |
不重复结合 | set< Type > | st.insert() | 无(只有同其他类型一样的删除erase) | 无(只有同其他类型一样的头迭代器st.begin()和尾迭代器st.end()) | ①st.erase(val);//删除set中值为val的元素 ②st.erase(iter);//删除迭代器iter指向的元素 ③st.erase(iter1, iter2);//删除迭代器itera核iter2范围内的所有元素(不包含iter2) | set比较特殊,解释请看博客后文第三部分 |
参考: CSDN博主【WhiteJunior】的文章C++中priority_queue理解与使用
priority_queue
直译名为优先队列,直接作用是最大堆。
作为队列的一个延伸,优先队列包含在头文件 < queue > 中。
priority_queue< type, container, function >
后面两个参数可以省略。
其中:
type:数据类型;
container:实现优先队列的底层容器;
function:元素之间的比较方式;
对于container,要求必须是数组形式实现的容器,例如vector、deque,而不能使list。
在STL中,默认情况下(不加后面两个参数)是以vector为容器,以 operator <(小于号,则队顶为最大值) 为比较方式,所以在只使用第一个参数时,优先队列默认是一个最大堆,每次输出的堆顶元素是此时堆中的最大元素。
优先队列时一种比较重要的数据结构,它是有二项队列编写而成的,可以以O(log n) 的效率查找一个队列中的最大值或者最小值,其中是最大值还是最小值是根据创建的优先队列的性质、也就是由 人为设定的比较函数(上述第三个参数function) 来决定的。
入 | 出 | 顶 |
---|---|---|
Q.push() | Q.pop() | Q.top() |
方法一: 把待输入的元素全都取相反数,如{1, -2, 3} 变为{-1, 2, -3}这样再存到priority_queue中,它就变成了原数组的一个最小堆,只是数字变成了原数组的相反数。
方法二: 自定义如1中所述模板参数的第三个参数,把比较函数设为大于比较,即函数作用与**opertor >**相同,则变成了最小堆。
示例1:
priority_queue<int, vector<int>, greater<int>> q;
示例2:
//重载操作符 < 或 >
1 #include <iostream>
2 #include <queue>
3 using namespace std;
4 struct Node{
5 int x, y;
6 Node(int a=0, int b=0):
7 x(a),y(b){}
8 };
9 bool operator<(Node a, Node b){//返回true时,说明a的优先级低于b
10 //x值较大的Node优先级低(x小的Node排在队前)
11 //x相等时,y大的优先级低(y小的Node排在队前)
12 if( a.x== b.x ) return a.y> b.y;
13 return a.x> b.x;
14 }
15 int main(){
16 priority_queue<Node> q;
17 for( int i= 0; i< 10; ++i )
18 q.push( Node( rand(), rand() ) );
19 while( !q.empty() ){
20 cout << q.top().x << ' ' << q.top().y << endl;
21 q.pop();
22 }
23 return 0;
24 }
示例3:
//写一个新的结构体
1 #include <iostream>
2 #include <queue>
3 using namespace std;
4 struct Node{
5 int x, y;
6 Node( int a= 0, int b= 0 ):
7 x(a), y(b) {}
8 };
9 struct cmp{
10 bool operator() ( Node a, Node b ){//默认是less函数
11 //返回true时,a的优先级低于b的优先级(a排在b的后面)
12 if( a.x== b.x ) return a.y> b.y;
13 return a.x> b.x; }
14 };
15 int main(){
16 priority_queue<Node, vector<Node>, cmp> q;
17 for( int i= 0; i< 10; ++i )
18 q.push( Node( rand(), rand() ) );
19 while( !q.empty() ){
20 cout << q.top().x << ' ' << q.top().y << endl;
21 q.pop();
22 }
23 return 0;
24 }
示例4:(leetcode 3 / 14 周赛:最大平均通过率)
//在以下程序中,priority_queue保存的是tuple类型,则它先按tuple的第一个元素排序;若第一个元素相等,再按第二个元素排序;若第二个也相等,再按第三个元素排序。
class Solution {
public:
double maxAverageRatio(vector<vector<int>>& classes, int extraStudents) {
priority_queue<tuple<double, int, int>> q;
auto diff = [](int x, int y) -> double {
return (double)(x + 1) / (y + 1) - (double)x / y;
};
double ans = 0;
int length = classes.size();
for(int i = 0; i < length; i++)
{
ans += (double)classes[i][0] / classes[i][1];
q.emplace(diff(classes[i][0], classes[i][1]), classes[i][0], classes[i][1]);
}
for(int i = 0; i < extraStudents; i++)
{
auto[d, x, y] = q.top();
q.pop();
ans += d;
q.emplace(diff(x+1, y+1), x+1, y+1);
}
return ans/length;
}
};
priority_queue不能用下标取值,即没有priority_queue[i]
操作。
参考: CSDN博主【千寻~】的文章deque用法详解
deque
直译名为双向队列,包含在头文件 < deque > 中。
deque< Type >
deque是一个线性双向队列,既可以从头插入、也可以从尾插入;同样,既可以从头删除,也可以从尾删除。当然,还包含对任意位置的插入删除操作。
由于其是双向链表,因此一切操作都有前(front)、后(back)两种。
入 | 出 | 顶 |
---|---|---|
Q.push_front() | Q.pop_front() | Q.front() |
Q.push_back() | Q.pop_back() | Q.back() |
set
为不重复集合,包含在头文件 < set > 中。
set< Type >
set
为不重复集合,即如果有两个一样的元素想要存入set,则set只会保留其中一个;且set会自动为其保存的元素进行排序。
set比较特殊,并不以push
为插入,而是以insert
为插入,因为set会自动排序,所以不一定后插入的元素就保存在后边,所以不能取 push 之意,而要取 insert 之意。(push有往后插入的意思,而insert是往后或往任意位置插入均可)。
由于set会自动排序,那么我们也就难以确定它的最后一个元素是什么,所以set类型没有pop,只有erase作删除用。
入 | 出 | 顶 |
---|---|---|
st.insert() | 无(只有同其他类型一样的删除erase) | 无(只有同其他类型一样的头迭代器st.begin()和尾迭代器st.end()) |