一个很简单的数据结构,但上午我还写错了,写这篇文章只是为了整理一下思路。参考:《算法导论》,《挑战程序设计》
什么是优先队列
百度百科
队列是一种特殊的线性表, 特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。
个人解释
通俗来讲就是一堆数列,比如1 2 3 4 5。有两个针对这堆数的操作
1:删除并返回队首的元素,常写作int pop()函数。
2:从队尾加入元素,常写作void push(int x)函数。
这样子的话,先入队的元素,就会先出队。与先入后出的栈相反。
优先队列
在队列的基础上,每次执行pop操作的时候,返回队列中最小或者最大的数。既然这样,那执行push操作的时候,也需要有相应的改变,不是单纯的往队尾加入元素了。
二叉堆
就是一棵完全二叉树,但是每个父亲节点的值都要比两个子节点的值要大或者小。
构建堆的时候,用的是一个足够大的数组,0下标表示根节点。假设某个节点的下标为i,则它的左儿子下标为i * 2 + 1,右儿子的下标为i * 2 + 2
实现
优先队列的实现,就是构造一个二叉堆
- 执行push操作的时候,在树的底层加入一个节点,然后通过该子节点和父亲节点的对比交换,将它放到适当的位置,使得它比父亲节点小,比子节点大。
- 执行pop操作的时候,返回树根部的元素,然后将最末端的节点提到根部,并向下插入,放到合适的位置。
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <ctime>
#define maxn 1000
using namespace std;
class priority_queque{
private:
int a[maxn];
int sz = 0;
int id;
int pre;
public:
void push(int x){
//自己的编号
int i = sz++;
while (i > 0){
//父亲节点的编号
int p = (i - 1) / 2;
if (a[p] <= x) break;//如果父亲节点已经小于自己了,那就可以退出了
a[i] = a[p];
i = p;
}
a[i] = x;
}
int pop(){
//最小值
int t = a[0];
//要提到根上的值
int x = a[--sz];
//从根开始向下交换
int i = 0;
while (i * 2 + 1 < sz){
//比较儿子的值
int l = i * 2 + 1;
int r = i * 2 + 2;
//令l变成最小儿子的编号
if (r < sz && a[r] < a[l]) l = r;
if (a[l] >= x) break;
a[i] = a[l];
i = l;
}
a[i] = x;
return t;
}
void print(){
for (int i = 0; i < sz; i++){
cout << a[i] << " ";
}
cout << endl;
}
};
int main(){
srand((unsigned)time(NULL));
priority_queque a;
for (int i = 5; i >= 1; i--){
int x = rand()% 100;
printf("%d\n", x);
a.push(x);
}
a.print();
for (int i = 0; i < 5; i++){
printf("%d, ", a.pop());
}
}