加工并存储数据的数据结构
堆
能够高效的利用二叉树解决 类似于优先队列操作的问题的数据结构叫 堆
优先队列:
- 只能从队尾插入元素,从队首删除元素。
- 但是它有一个特性,就是队列中最大的元素总是位于队首,所以出队时,并非按照先进先出的原则进行,而是将当前队列中最大的元素出队。
- 这点类似于给队列里的元素进行了由大到小的顺序排序。元素的比较规则默认按元素值由大到小排序,可以重载“<”操作符来重新定义比较规则。
堆:
1
/ \
2 4
/ \ / \
7 8 5
- 推最重要的性质是儿子的值一定不小于父亲的值,除此之外,数的节点从上到下,从左至右的顺序紧凑排列的。
- 插入一个数值:首先在堆的末尾插入数值,然后不断向上提升直到没有大小颠倒为止。
- 取出一个最小的数值(并且删除):首先把堆的最后一个节点的数值复制到根节点上,并且删除最后一个节点。然后不断向下交换直到没有大小颠倒为止,在向下交换的过程中,如果有两个儿子,选择数值较小的儿子进行交换。
堆的时间复杂度:
堆的两种操作所花的时间都与数的深度成正比,如果一共有n个元素,每个操作进行都能在 O(logn)的时间内完成。
堆的实现
vector<int> heap;
void push(int x){
heap.push_back(x);
int i=heap.size();
while(i > 0){
int p=(i-1)/2;
if(heap.at(p) >= x) break;
heap.at(i) = heap.at(p);
i = p;
}
heap.at(i)=x;
}
int pop(){
//最小值
if(heap.size()==0) return -1;
int ret = heap.at(0);
int x = heap.back();
heap.erase(heap.cend()-1);
int i=0;
while(i*2+1 < heap.size()){
int l=i*2+1,r=l+1;
if(r<heap.size() && heap.at(r) < heap.at(l)) l=r;
//如果没有大小颠倒则退出
if(x <= heap.at(l)) break;
//把儿子的数值提升上来
heap.at(i) = heap.at(l);
i = l;
}
heap.at(i) = x;
return ret;
}
标准库优先队列
C++中,STL里的 priority_queue就是优先队列 ,但是取出数值时得到的是最大值。
int main()
{
//声明并执行默认初始化
priority_queue<int> pque;
//插入元素
pque.push(3);
pque.push(5);
pque.push(1);
while(!pque.empty()){
cout<<pque.top()<<ends;
pque.pop();
}
return 0;
}
需要用到优先队列的题目
Expedition(POJ 2431)
描述:你需要驾驶一辆卡车行驶 L 单位距离。 最开始时, 卡车上有 P 单位 的汽油。 卡车每开 1 单位距离需要消耗 1 单位的汽油 。 如果在途中车上的汽油耗尽 , 卡车就无法继续前行, 因而无法到达终点。 在途中一共有 N个加油站。 第 i 个加油站在距离起点 Ai单位距离的地方,最多可以给卡车加 Bi单位汽油,假设卡车的燃料箱的容量是无限大的 , 无论加多少油都没问题 。 那么请问卡车能否到达终点? 如果可以,最少需要加多少次油?如果可以到达终点,输出最少的加油次数,否则输出 -1.。
限制条件:
- 1 <= N <= 10000
- 1 <= L <= 1000000, 1<= P <=1000000
- 1 <= Ai < L , 1 <= Bi <=100
题解:由于加油站的数量N很大,必须想一个高效的算法。
思路:”我们在达到加油站时,就获得了一次在之后的任何时候加 Bi单位油的权力 “,这样的思路,我们将现有的油耗尽,添加已经经历过的加油站所能加的油量,存入优先队列,以从大到小的顺序,保证加油最小次数。
代码:
int Solve(int N,int L,int P,const vector<int> &A,const vector<int> &B){
// 1.遍历全部途中的加油站,如果当前存放油量大于其位置,就添加该加油站点能加的油存入优先队列中
// 2.油空了 @1:如果优先队列也是空的,则无法到达终点 @2:否则取出加油。
int res = 0;
priority_queue<int> pque;
for (int i = 0; i !=N; ++i) {
if(P < A.at(i) ){
if(pque.size() == 0) return -1;
P+=pque.top();
pque.pop();
++res;
if(P>=L)