队列 queue
------ 用法概括
· 实质:对于队列 queue a 数组,可以形象地看作 一个队列,而操作指令可以看作 排队的过程,始终遵循 先进先出 的原则
------ 指令概况
方法 | 描述 | 示例 | 时间复杂度 |
---|---|---|---|
push | 队尾入队 | q.push(x) | O(1) |
pop | 队首出队 | q.pop() | O(1) |
front | 返回队首元素 | q.front() | O(1) |
back | 返回队尾元素 | q.back() | O(1) |
优先队列 priority_queue
------ 用法概括
· 实质:可以看作 大根堆,对于较大的元素会被放在堆顶,实现 自动排序
priority_queue<int> q;
int main() {
int x;
for(int i=1; i<=5; i++) {
scanf("%d",&x);
q.push(x);
}
for(int i=1; i<=5; i++) {
printf("%d ",q.top());
q.pop();
}
return 0;
}
输入内容:5 -4 5 0 9
输出结果:9 5 5 0 -4
· 附加理解:priority_queue 优先队列将原本杂乱无章的序列 S:4 2 5 1 3,通过 “<” 运算符将较大元素放在堆顶,自动排序得到新序列 S’:1<2<3<4<5,此时 5 为堆顶元素 (认真体会对重载运算符原理理解更深)
------ 指令概括
方法 | 描述 | 示例 | 时间复杂度 |
---|---|---|---|
push | 把元素插入堆 | q.push(x) | O(1) |
pop | 删除堆顶元素 | q.pop() | O(1) |
top | 返回堆顶元素(最大值) | q.top() | O(1) |
------ priority_queue 实现小根堆
· 引:已知 priority_queue 是将 较大元素 放在堆顶,那应如何将 较小元素 放入堆顶,即小根堆:
1. 把 插入元素 取相反数,取出堆顶元素(最大值)时,再次把其取相反数,从而得到原来的元素。
由于相反数的性质,插入原元素的相反数后(设为新元素)
此时优先队列堆顶为 最大新元素(即最小原元素),此时的堆顶为 最小原元素(堆顶新元素取反后)
2. 我们可以直接声明 “大根堆”与“小根堆”,以 int 类型为例
priority_queue<int,vector<int>,greater<int> > q; //小根堆,堆顶元素最小
priority_queue<int,vector<int>,less<int> > p; //大根堆,堆顶元素最大
注:此处 “>” 符号不能相连,否则会被系统当作 位移运算符,直接报错
------ 重载运算符
· 实质:在 priority_queue 中储存的元素按照 从大到小 排序,内部实现就是依靠 “<” 运算符,则较大值会被放在堆顶
内置的 int和string 类型本身就可以比较大小,对于自定义的结构体,则需要重载 “<” 运算符的比较方式
bool operator 重载运算符 (const 自定义结构体类型 &a,const 自定义结构体类型 &b) {
return 重载运算符比较的规则 ; }
struct node {
int id;
double x;
}a[10];
priority_queue<node> q;
bool operator <(const node &a,const node &b) { /*注意上文的附加理解
此时 "<" 运算符将 浮点型 x较大的元素 放在堆顶*/
return a.x>b.x; //关于浮点型比大小,会出现精度误差,此处省略(偷懒)
}
int main() {
for(int i=1; i<=5; i++) {
scanf("%lf",&a[i].x);
a[i].id=i;
q.push(a[i]);
}
for(int i=1; i<=5; i++) {
printf("%d ",q.top().id);
q.pop();
}
return 0;
}
输入内容:
0.1
0.01
5.2
5.4
0.1
输出结果:4 3 1 5 2
· 附加:对于 C++ 内置的二元组 pair < 结构类型 > (make_pair 函数创建二元组,成员变量 first 访问第一元,second 访问第二元) 在优先队列中比较大小时,以第一元为第一关键字,第二元为第二关键字