priority_queue
1.priirity_queue优先级队列是一种容器适配器。
2.priority_queue底层的数据结构是vector,通过堆算法来来排序从而实现优先级队列
3.默认情况下,priority_queue是大堆(降序)
模拟实现代码如下:
//PriorityQueue.h
#pragma once
#include<vector>
namespace yqx
{
template<class T>
class Less
{
public:
bool operator()(const T& x, const T& y)const
{
return x < y;
}
};
template<class T>
class Greater
{
public:
bool operator()(const T& x, const T& y)const
{
return x > y;
}
};
template<class T, class Container = vector<T>,class Compar = Less<T>>
class priority_queue
{
public:
priority_queue()
{
}
template <class InputIterator>//迭代器范围初始化
priority_queue(InputIterator first, InputIterator last)
{
//将数据插入
while (first != last)
{
_con.push_back(*first);
++first;
}
//建堆
for (int i = (_con.size() - 2) / 2; i >= 0; --i)
{
AdjustDown(i);
}
}
size_t size()const
{
return _con.size();
}
void Adjustup(size_t child)
{
Compar com;//仿函数定义对象
size_t parent = (child - 1) / 2;
while (child > 0)
{
if (com(_con[parent],_con[child]))
{
swap(_con[child], _con[parent]);
child = parent;
parent = (child - 1) / 2;
}
else
break;
}
}
void AdjustDown(size_t parent)
{
Compar com;//仿函数定义对象
size_t child = 2 * parent + 1;
while (child<_con.size())
{
if (child + 1<_con.size() && com(_con[child], _con[child + 1]))
{
child++;
}
if (com(_con[parent] , _con[child]))
{
swap(_con[parent], _con[child]);
parent = child;
child = 2 * parent + 1;
}
else
break;
}
}
void push(const T& x)
{
_con.push_back(x);
Adjustup(_con.size() - 1);
}
void pop()
{
swap(_con[0], _con[_con.size() - 1]);
_con.pop_back();
AdjustDown(0);
}
const T& top()
{
return _con[0];
}
bool empty()
{
return _con.empty();
}
private:
Container _con;
};
}
//Test.cpp(测试用例)
#include<iostream>
using namespace std;
#include<queue>
#include<vector>
#include<functional>
#include"PriorityQueue.h"
//使用库函数中的priority_queue
//int main()
//{
// priority_queue<int, vector<int>, less<int>> lt;
// lt.push(2);
// lt.push(1);
// lt.push(3);
// lt.push(5);
// lt.push(4);
// while (!lt.empty())
// {
// cout << lt.top() << " ";
// lt.pop();
// }
// cout << endl;
// return 0;
//}
//打印容器中的元素
//tpyename的使用会在代码块下边做以简单介绍
template<class Container>
void PrintContainer(const Container& p)
{
typename Container::const_iterator it = p.begin();
while (it != p.end())
{
cout << *it << " ";
++it;
}
cout << endl;
}
class Date
{
public:
Date(int year = 1990,int month = 1 ,int day =1)
:_year(year)
,_month(month)
,_day(day)
{
}
bool operator<(const Date& d)const
{
return (_year < d._year) ||
(_year == d._year && _month < d._month) ||
(_year == d._year && _month == d._month && _day < d._day);
}
friend ostream& operator<<(ostream& out, const Date& d);
friend class PDateLess;
private:
int _year;
int _month;
int _day;
};
ostream& operator<<(ostream& out, const Date& d)//日期类输出重载
{
cout << d._year << "-" << d._month << "-" << d._day;
return out;
}
class PDateLess
{
public:
bool operator()(const Date* p1, const Date* p2)const
{
/* return (p1->_year < p2->_year) ||
(p1->_year == p2->_year && p1->_month < p2->_month) ||
(p1->_year == p2->_year && p1->_month == p2->_month && p1->_day < p2->_day);*/
return *p1 < *p2;
}
};
int main()
{
//将类作为priority_queue初始化构造的元素
/*yqx::priority_queue<Date,vector<Date>,DateLess> lt;
lt.push(Date(2020, 12, 23));
lt.push(Date(2020, 11, 25));
lt.push(Date(2020, 12, 24));
lt.push(Date(2020, 11, 22));
cout << lt.top() << endl;
lt.pop();*/
//使用类的指针来构造priority_queue
yqx::priority_queue<Date*,vector<Date*>,PDateLess> lt;
lt.push(new Date(2020, 12, 23));
lt.push(new Date(2020, 11, 25));
lt.push(new Date(2020, 12, 24));
lt.push(new Date(2020, 11, 22));
cout << *lt.top() << endl;
lt.pop();
/*yqx::priority_queue<int, vector<int>> lt;
lt.push(2);
lt.push(1);
lt.push(3);
lt.push(5);
lt.push(4);
while (!lt.empty())
{
cout << lt.top() << " ";
lt.pop();
}
cout << endl;
//C++11中初始化构造容器的新方法
vector<int> l = { 1,2,5,7,6,10,8 };
//打印某个容器中的元素
PrintContainer(l);
//使用某个容器的迭代器范围来初始化构造priority_queue
yqx::priority_queue<int, vector<int>, greater<int>> llt(l.begin(),l.end());
while (!llt.empty())
{
cout << llt.top() << " ";
llt.pop();
}
cout << endl;*/
return 0;
}
关键字typename的使用
//typename的使用
template<class Container>
void PrintContainer(const Container& p)
{
Container::const_iterator it = p.begin();
while (it != p.end())
{
cout << *it << " ";
++it;
}
cout << endl;
}
对于用于模板定义的依赖于模板参数的名称,只有在实例化的参数中存在这个类型名,或者这个名称前使用了 typename 关键字来修饰,编译器才会将该名称当成是类型。除了以上这两种情况,绝不会被当成是类型。
因此,如果你想直接告诉编译器 T::const_iterator 是类型而不是变量,只需用 typename修饰:
typename Container::const_iterator it = p.begin();
typename Container::const_iterator it (p.begin());
加上typename之后,编译器就会知道这是个类型,而不再需要等到实例化时期才能确定。
初识仿函数
仿函数(Functor)又称为函数对象(Function Object)是一个能行使函数功能的类。仿函数的语法几乎和我们普通的函数调用一样,不过作为仿函数的类,都必须重载operator()运算符。因为调用仿函数,实际上就是通过类对象调用重载后的operator()运算符。
如果要将某种“操作”当做算法的参数,一般有两种方法:
(1)先将该“操作”设计为一个函数,再将函数指针当做算法的一个参数。
(2)将该“操作”设计为一个仿函数(就语言层面而言是个class),再以该仿函数产生一个对象,并以此对象作为算法的一个参数。
很明显第二种方法会更优秀,在我们写代码时有时会发现有些功能代码,会不断地被使用。为了复用这些代码,实现为一个公共的函数是一个解决方法。不过函数用到的一些变量,可能是公共的全局变量。引入全局变量,容易出现同名冲突,不方便维护。
仿函数的优点:
仿函数是模板函数,.在同一时间里,由某个仿函数所代表的单一函数,可能有不同的状态,可以根据不同的类型代表不同的状态
仿函数是模板函数,所以仿函数即使定义相同,也可能有不同的类型
仿函数是模板函数,仿函数通常比一般函数速度慢
仿函数使程序代码变简单,仿函数在一定程度上使代码更通用,本质上简化了代码