概述
目录
一,优先队列
二,STL优先队列
三,二叉堆实现优先队列
四,二项堆实现优先队列
五,线段树实现优先队列
六,OJ实战
力扣 295. 数据流的中位数
一,优先队列
优先队列可以插入元素、查询最大值、删除最大值。
优先队列其实就是最大堆或最小堆,最大堆可以用来实现最大优先队列,最小堆可以用来实现最小优先队列。
用各种堆都可以实现优先队列。
二,STL优先队列
优先队列如果要自定义排序函数,只能用仿函数,不能用普通函数的指针。
示例:
#include<iostream>
#include<queue>
#include<functional>
using namespace std;
class cmp
{
public:
bool operator()(int a, int b)
{
return a < b;
}
};
bool cmp2(int a, int b)
{
return a < b;
}
template <typename A>
void display()
{
A q;
q.push(1);
q.push(3);
q.push(4);
q.push(2);
while (!q.empty())
{
cout << q.top();
q.pop();
}
cout << endl;
}
int main()
{
display < priority_queue<int, vector<int>> >(); //默认大顶堆
display < priority_queue <int, vector<int>, greater<int>> >();//小顶堆
display < priority_queue <int, vector<int>, less<int>> >();//大顶堆
display < priority_queue<int, vector<int>, cmp>>();//大顶堆
//display < priority_queue<int, vector<int>, cmp2>>(); 错误
return 0;
}
输出:
4321
1234
4321
4321
附上priority_queue的实现代码:
// TEMPLATE CLASS priority_queue
template<class _Ty,
class _Container = vector<_Ty>,
class _Pr = less<typename _Container::value_type> >
class priority_queue
{ // priority queue implemented with a _Container
public:
......
一堆函数
......
protected:
_Container c; // the underlying container
_Pr comp; // the comparator functor
};
可以看出模板参数_Pr的默认值是less,也就是说默认排序函数是less函数。
priority_queue中包含一个排序的序列,堆顶是这个序列的最后一个元素,所以从小到大排序是大顶堆,从大到小排序是小顶堆。
三,二叉堆实现优先队列
二叉堆
最大优先队列:
#include<iostream>
#include <vector>
using namespace std;
template<typename T>
bool cmp(T a, T b)
{
return a < b; //最大堆
}
template<typename T>
void exchange(T* a, T* b)
{
T tmp = *a;
*a = *b;
*b = tmp;
}
int LeftChild(int id)
{
return id * 2;
}
int RightChild(int id)
{
return id * 2 + 1;
}
int Parent(int id)
{
return id/2;
}
template<typename T>
void AdjustHeap(T* arr, int rootId, int size)
{
int largest = rootId, left = LeftChild(rootId), right = RightChild(rootId);
if (left < size && cmp(arr[largest], arr[left]))largest = left;
if (right < size && cmp(arr[largest], arr[right]))largest = right;
if (largest == rootId)return;
exchange(arr + rootId, arr + largest);
AdjustHeap(arr, largest, size);
}
template<typename T>
void HeapIncrese(T* arr, int size, int id, T newValue)
{
arr[id] = newValue;
while (id > 0 && cmp(arr[Parent(id)], arr[id])) {
exchange(arr + id, arr + Parent(id));
id = Parent(id);
}
}
template<typename T>
void HeapInsert(T* arr, int &size,T value)
{
HeapIncrese(arr,size+1,size,value);
size++;
}
int g_size;
void Init()
{
g_size = 0;
}
template<typename T>
T Top(T* arr)
{
return arr[0];
}
template<typename T>
void Push(T* arr, T value)
{
HeapInsert(arr,g_size,value);
}
template<typename T>
void Pop(T* arr)
{
g_size--;
exchange(arr, arr+g_size);
AdjustHeap(arr, 0, g_size);
}
int main()
{
int q[10];
Init();
Push(q,4);
Push(q,2);
Push(q,6);
Push(q,3);
Push(q,4);
Push(q,5);
cout<<Top(q)<<" ";
Pop(q);
cout<<Top(q)<<" ";
Pop(q);
cout<<Top(q)<<" ";
Pop(q);
cout<<Top(q)<<" ";
Pop(q);
cout<<Top(q)<<" ";
Pop(q);
cout<<Top(q)<<" ";
Pop(q);
cout<<endl<<g_size;
return 0;
}
运行结果:
6 5 4 4 3 2
0
四,二项堆实现优先队列
二项堆 里面已经实现了push、pop、top等操作,所以它就是一种优先队列。
五,线段树实现优先队列
代码:
struct anode
{
int t;
int d;
};
int n;
int num[10001],maxx[40001];
struct anode node[10001];
void build(int key, int low, int high)//id
{
if (low == high)
{
maxx[key] = low;
return;
}
int mid = (low + high) / 2;
build(key * 2, low, mid);
build(key * 2 + 1, mid + 1, high);
maxx[key] = (num[maxx[key * 2]] > num[maxx[key * 2 + 1]]) ? maxx[key * 2] : maxx[key * 2 + 1];
}
void update(int key, int low, int high, int uplace)//id
{
if (low == high)
{
maxx[key] = low;
return;
}
int mid = (low + high) / 2;
if (uplace <= mid)update(key * 2, low, mid, uplace);
else update(key * 2 + 1, mid + 1, high, uplace);
maxx[key] = (num[maxx[key * 2]] > num[maxx[key * 2 + 1]]) ? maxx[key * 2] : maxx[key * 2 + 1];
}
int query(int key, int low, int high, int x, int y)//id
{
if (low == x && high == y)return maxx[key];
int mid = (low + high) / 2;
if (mid < x)return query(key * 2 + 1, mid + 1, high, x, y);
if (mid >= y)return query(key * 2, low, mid, x, y);
int a = query(key * 2, low, mid, x, mid);
int b = query(key * 2 + 1, mid + 1, high, mid + 1, y);
return (num[a]>num[b]) ? a : b;
}
void push(int loc)
{
num[loc]=node[loc].t; ///根据实际情况修改
update(1,1,n,loc);
}
void pop(int loc)
{
num[loc]=0; ///根据实际情况修改
update(1,1,n,loc);
}
int top()//id
{
return query(1,1,n,1,n);
}
应用:
力扣 630. 课程表 III
六,OJ实战
力扣 295. 数据流的中位数
中位数是有序列表中间的数。如果列表长度是偶数,中位数则是中间两个数的平均值。
例如,
[2,3,4] 的中位数是 3
[2,3] 的中位数是 (2 + 3) / 2 = 2.5
设计一个支持以下两种操作的数据结构:
void addNum(int num) - 从数据流中添加一个整数到数据结构中。
double findMedian() - 返回目前所有元素的中位数。
示例:
addNum(1)
addNum(2)
findMedian() -> 1.5
addNum(3)
findMedian() -> 2
思路:
维护1个最大堆和1个最小堆,并动态维持他们的尺寸相同。
class MedianFinder {
public:
MedianFinder() {
}
void addNum(int num) {
if (qmax.empty()||num<=qmax.top())qmax.push(num);
else qmin.push(num);
}
double findMedian() {
while (qmin.size() > qmax.size()) qmax.push(qmin.top()),qmin.pop();
while (qmax.size() > qmin.size()+1)qmin.push(qmax.top()),qmax.pop();
if (qmax.size() > qmin.size())return qmax.top();
return (qmax.top() + qmin.top()) / 2.0;
}
private:
priority_queue<int, vector<int>> qmax;
priority_queue <int, vector<int>, greater<int>> qmin;
};
或者用自己实现的堆:
template<typename T>
class MyHeap {
public:
T arr[100000];
MyHeap(int type)//0最小堆1最大堆
{
this->type = type;
}
T Top()
{
return arr[0];
}
void Push(T value)
{
HeapInsert(arr, value);
}
void Pop()
{
size--;
exchange(arr, arr + size);
AdjustHeap(arr, 0);
}
bool empty()
{
return size == 0;
}
int Size()
{
return size;
}
private:
void AdjustHeap(T* arr, int rootId)
{
int largest = rootId, left = LeftChild(rootId), right = RightChild(rootId);
if (left < size && cmp(arr[largest], arr[left]))largest = left;
if (right < size && cmp(arr[largest], arr[right]))largest = right;
if (largest == rootId)return;
exchange(arr + rootId, arr + largest);
AdjustHeap(arr, largest);
}
void HeapIncrese(T* arr, int id, T newValue)
{
arr[id] = newValue;
while (id > 0 && cmp(arr[Parent(id)], arr[id])) {
exchange(arr + id, arr + Parent(id));
id = Parent(id);
}
}
void HeapDecrese(T* arr, int size, int id, T newValue)
{
arr[id] = newValue;
AdjustHeap(arr, id, size);
}
void HeapChange(T* arr, int id, T newValue)
{
if (cmp(arr[id], newValue))HeapIncrese(arr, id, newValue);
else HeapDecrese(arr, id, newValue);
}
void HeapInsert(T* arr, T value)
{
HeapIncrese(arr, size++, value);
}
bool cmp(T a, T b)
{
return type ? (a < b) : (a > b);
}
void exchange(T* a, T* b)
{
T tmp = *a;
*a = *b;
*b = tmp;
}
int LeftChild(int id)
{
return id * 2 + 1;
}
int RightChild(int id)
{
return id * 2 + 2;
}
int Parent(int id)
{
return (id - 1) / 2;
}
int type;
int size = 0;
};
class MedianFinder {
public:
MedianFinder() {
}
void addNum(int num) {
if (qmax.empty() || num <= qmax.Top())qmax.Push(num);
else qmin.Push(num);
}
double findMedian() {
while (qmin.Size() > qmax.Size()) qmax.Push(qmin.Top()), qmin.Pop();
while (qmax.Size() > qmin.Size() + 1)qmin.Push(qmax.Top()), qmax.Pop();
if (qmax.Size() > qmin.Size())return qmax.Top();
return (qmax.Top() + qmin.Top()) / 2.0;
}
private:
MyHeap<int> qmax{ 1 };
MyHeap<int> qmin{ 0 };
};
其他应用:
A算法
CSU 1588 合并果子
CCF-CSP-2017-3-4 地铁修建
力扣 347. 前 K 个高频元素
力扣 373. 查找和最小的K对数字
力扣 378. 有序矩阵中第K小的元素
力扣 1090. 受标签影响的最大值
力扣 1631. 最小体力消耗路径
力扣 451. 根据字符出现频率排序
2020编码大赛(2)初赛
最后
以上就是如意枕头为你收集整理的优先队列(priority queue)一,优先队列二,STL优先队列三,二叉堆实现优先队列四,二项堆实现优先队列五,线段树实现优先队列六,OJ实战的全部内容,希望文章能够帮你解决优先队列(priority queue)一,优先队列二,STL优先队列三,二叉堆实现优先队列四,二项堆实现优先队列五,线段树实现优先队列六,OJ实战所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复