文章目录
- 前言
- 1、优先级队列的使用?
- 2、仿函数?
- 3、优先级队列用仿函数实现大/小堆变换?
前言
priority_queue:优先级队列,别看有一个队列的名字,但结构个队列完全不一样。队列是一种先进先出的结构特征,然而这里的优先级队列,此结构是一种堆的结构,但是用vector形式存储数据的。以堆的结构来实现该优先级队列,可以在每次top堆顶元素的时候都是最大或最小的元素,可以应用于top_k问题,即返回一个大量数据中前K个较大的元素值。接下来就来了解了解优先级队列吧!
1、优先级队列的使用?
对优先级队列的插入、删除、判空等函数的使用。
#include<iostream>
#include<queue>
using namespace std;
//优先级的队列头文件就是queue
void test()
{
priority_queue<int> pq;
pq.push(10);
pq.push(66);
pq.push(1);
pq.push(6);
pq.push(12);
pq.push(87);
pq.push(45);
pq.push(23);
cout << "优先级队列的数据个数:" << pq.size() << endl;
while (!pq.empty())
{
cout << pq.top() << " ";
pq.pop();
}
}
int main()
{
test();
return 0;
}
输出结构就是从大到小的,因为默认是建立的大堆。
传入的是less(仿函数),就是插入的数据小于父节点就上调的,从而建立大堆。然后依次top堆顶元素就是大的数据。
2、仿函数?
仿函数实质是一个类,是一个什么类呢?
是一种重载了函数调用运算符operator()的类或结构体,它可以使一个类的使用看上去像一个函数。仿函数可以接受参数并返回值,可以用于STL算法中的函数对象参数,也可以用于函数指针的替代。仿函数的主要作用包括:
①提供一种灵活的方式来实现函数对象,可以根据实际需求定制自己的函数对象,比如排序、查找等算法。
②封装函数参数,使得算法可以接受不同类型的参数,增加算法的通用性。
③保存状态,在多次调用之间保持状态,避免每次调用时都需要重新计算。
④替代函数指针,因为函数指针只能指向全局函数或静态成员函数,而仿函数可以指向任意类型的函数,包括成员函数和非静态成员函数。下面是一个仿函数的例子:
template<class T>
class Less
{
public:
bool operator()(const T& x,const T& y)
{
return x < y;
}
};
template<class T>
class Greater
{
public:
bool operator()(const T& x, const T& y)
{
return x > y;
}
};
template<class T,class Compare>
void BubbleSort(vector<T>& v,Compare com)
{
int i = 0, j = 0;
for (i = 0; i < v.size(); i++)
{
int flag = 0;
for (j = 1; j < v.size() - i; j++)
{
if (com(v[j], v[j - 1]))
{
swap(v[j-1],v[j]);
flag = 1;
}
}
if (flag == 0)
{
break;
}
}
}
int main()
{
vector<int> v;
v.push_back(5);
v.push_back(7);
v.push_back(8);
v.push_back(1);
v.push_back(0);
v.push_back(2);
v.push_back(6);
v.push_back(9);
BubbleSort(v, Less<int>());//此处是匿名对象传参的,也可以先创建Less less;
auto it1 = v.begin();
while (it1 != v.end())
{
cout << *it1 << " ";
++it1;
}
return 0;
}
结果就是一个升序:
3、优先级队列用仿函数实现大/小堆变换?
首先要知道优先级队列是使用vector容器存储数据,结构上是堆。默认是建大堆。
实现思路:
①插入函数:每当插入一个数据,就向上调整,保证每插入一个数据依然是大堆。
②删除函数:不是直接删除堆顶元素,而是先交换堆顶元素和末尾元素。然后直接删除最后一个数据,之后再做向下调整。
③返回top元素:由于是vector容器存储的数据,即直接返回下标为0的数据即可。
④求数据个数:直接调用size()函数
⑤判空:直接调用vector的empty()函数。
#pragma once
namespace zc
{
template<class T>
class Less
{
public:
bool operator()(const T& x,const T& y)
{
return x < y;
}
};
template<class T>
class Greater
{
public:
bool operator()(const T& x, const T& y)
{
return x > y;
}
};
//template<class T,class Container=std::vector<T>>
template<class T, class Container = std::vector<T>,class Compare=Less<int>>
class Prority_queue
{
private:
//向上调整算法
void AdjustUp(size_t child)
{
//先计算父节点
size_t parent = (child - 1) / 2;
//调整
while (child > 0)
{
//判断,若孩子比父亲的值大,则交换
//if (_con[child] > _con[parent])
if (com(_con[parent],_con[child]))
{
std::swap(_con[child], _con[parent]);
//重新找父节点
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
//向下调整函数
void AdjustDown(int parent)
{
//计算孩子,由于要找大的数据,因此假设左孩子数据更大
int child = parent * 2 + 1;
//然后调整,直到孩子节点大于或等于数据个数
while (child < _con.size())
{
//判断和右孩子谁大
//if (child+1<_con.size()&&_con[child] < _con[child + 1])
if (child + 1 < _con.size() && com(_con[child] , _con[child + 1]))
{
child += 1;//变为右孩子的位置
}
//if (_con[parent] < _con[child])
if (com(_con[parent] , _con[child]))
{
std::swap(_con[parent],_con[child]);
//更新
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
public:
//先写插入函数
void push(const T& x)
{
_con.push_back(x);
//插入以后向上调整见大堆,从刚插入的位置开始调整
AdjustUp(_con.size()-1);
}
//删除函数
void pop()
{
//先交换堆顶元素和末尾的元素,再删除最后的一个元素
std::swap(_con[0],_con[_con.size()-1]);
_con.pop_back();
//再向下调整
AdjustDown(0);
}
const T& top()
{
return _con[0];
}
//计算大小
size_t size()const
{
return _con.size();
}
//判断是否为空
bool empty()const
{
return _con.empty();
}
private:
Container _con;
Compare com;
};
}
#include<iostream>
#include"PriorityQueue.h"
//自定义优先级队列
void test_06()
{
//zc::Prority_queue<int> pq;
//zc::Prority_queue<int> pq;//缺省值是vector<int>,Less<int>
zc::Prority_queue<int,std::vector<int>,zc::Greater<int>> pq;
pq.push(14);
pq.push(20);
pq.push(45);
pq.push(3);
pq.push(10);
pq.push(66);
pq.push(1);
pq.push(0);
std::cout << "自定义优先级队列数据个数:" << pq.size() << std::endl;
while (!pq.empty())
{
std::cout << pq.top() << " ";
pq.pop();
}
}
int main()
{
std::cout << "自定义的优先级队列:" << std::endl;
test_06();
std::cout << std::endl;
return 0;
}
比较大于:即升序
比较小于:降序