priority_queue的模拟实现
💦 priority_queue的模拟实现
💨PriorityQueue.h
#pragma once
#include<vector>
#include<list>
#include<iostream>
using namespace std;
namespace bit
{
//仿函数/函数对象——自定义类型,类型的对象可以像函数一样使用
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;
}
};
//模板参数->类型
//函数参数->对象
//less->大堆 greater->小堆,默认是Less
template<class T, class Container = vector<T>, class Compare = 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() - 1 - 1) / 2; i >= 0; --i)
{
AdjustDown(i);
}
}
void AdjustUp(size_t child)
{
Compare com;
size_t parent = (child - 1) / 2;
while (child > 0)
{
//if (_con[parent] < _con[child])
if (com(_con[parent], _con[child]))
{
swap(_con[parent], _con[child]);
child = parent;
parent = (child - 1) / 2;
}
else//父亲>=孩子
{
break;
}
}
}
void AdjustDown(size_t parent)
{
Compare com;
size_t 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;
}
//if (_con[parent] < _con[child])
if (com(_con[parent], _con[child]))
{
swap(_con[parent], _con[child]);
parent = child;
child = parent * 2 + 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() const
{
return _con[0];
}
size_t size()
{
return _con.size();
}
bool empty()
{
return _con.empty();
}
private:
Container _con;//构造析构等可以不写,因为这是自定义类型
};
void test_priority_queue()
{
//priority_queue<int> pq;
priority_queue<int, vector<int>, Greater<int>> pq;
pq.push(1);
pq.push(10);
pq.push(11);
pq.push(3);
pq.push(5);
pq.push(8);
while (!pq.empty())
{
cout << pq.top() << " ";
pq.pop();
}
cout << endl;
list<int> lt = { 2, 5, 1, 3, 4 };
priority_queue<int, vector<int>, greater<int>> pq1(lt.begin(), lt.end());
while (!pq1.empty())
{
cout << pq1.top() << " ";
pq1.pop();
}
cout << endl;
}
}
💨test.cpp
int main()
{
bit::test_priority_queue();
return 0;
}
📝说明
-
List item
在以前我们要让大堆变小堆,都是直接去改符号,那如何能不改符号的情况下就能达到效果呢 ❓
C语言其实可以利用函数指针来解决。但是 C++ 放弃用函数指针的方式,且非常不建议用函数指针,因为比较复杂。可以说 C++ 里的仿函数/函数对象就是为了替代 C语言里的函数指针。
“ () ” 的功能可以提高优先级、强制类型转换、函数名 (形参表),仿函数用的是函数名 (形参表)。我们实现两个类,分别重载 “ () ” 完成比较大小功能,然后用 priority_queue 这个类来实例化控制。


-
List item
对比 priority_queue 的仿函数和 <algorithm> 中 sort 的仿函数 ❗
priority_queue 是一个类,最好通过模板参数来传递,传的是类型。
这里 less 中给的是 typename Container::value_type,并没有很特别的原因,less 里可以直接给 T,因为它是取 Container 中的 value_type,value_type 是被 typedef 的第一个模板参数,也就是 T。我们要去 Container 中取 value_type。Container 是一个模板,不知道它具体是啥,因为 vector 没有被实例化,所以去取可能会报错,所以加上 typename 是告诉编译器,后面是一个类型,当然报错与否,主要看编译器。这里后面遇到合适的场景会再谈。

sort 是一个函数,最好通过参数来传递。
类模板是显示实例化的,所以说我们可以显示的指定参数;但是函数模板一般是通过实参去推演的,所以说 sort 得写在函数参数里。所以 priority_queue 是传类型,sort 是传对象。

💦 仿函数的变异玩法
要求往优先级队列里放一个日期类,且取出最大的日期 ❓
🧿 方案一:
#include<queue>
#include<iostream>
using namespace std;
class Date
{
public:
Date(int year = 2022, int month = 5, 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& _cout, const Date& d);
private:
int _year;
int _month;
int _day;
};
ostream& operator<<(ostream& _cout, const Date& d)
{
_cout << d._year << "-" << d._month << "-" << d._day << endl;
return _cout;
}
int main()
{
//我们可以放int,也可以放类
priority_queue<Date> pq;
pq.push(Date(2021, 11, 24));
pq.push(Date(2021, 10, 24));
pq.push(Date(2021, 12, 24));
pq.push(Date(2022, 1, 24));
//pq是自定义类型,所以上面需要重载<<,要取最大的日期,需要重载<
cout << pq.top() << endl;
pq.pop();
return 0;
}
🧿 方案二:
假设极端情况,如果存的是日期类指针呢,如果再用上面的方式,取不出来,因为它比的是地址。解决方案就是我们自己实现仿函数来控制。
#include<queue>
#include<iostream>
using namespace std;
class Date
{
public:
Date(int year = 2022, int month = 5, 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& _cout, const Date& d);
friend class PDateLess;
private:
int _year;
int _month;
int _day;
};
ostream& operator<<(ostream& _cout, const Date& d)
{
_cout << d._year << "-" << d._month << "-" << d._day << endl;
return _cout;
}
class PDateLess
{
public:
bool operator()(const Date* p1, const Date* p2)
{
/*if(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 true;
}
else
{
return false;
}*/
//同上,重载了<的情况
return *p1 < *p2;
}
};
int main()
{
priority_queue<Date*, vector<Date*>, PDateLess> pq;
pq.push(new Date(2023, 11, 24));
pq.push(new Date(2021, 10, 24));
pq.push(new Date(2021, 12, 24));
pq.push(new Date(2022, 1, 24));
cout << (*pq.top()) << endl;
pq.pop();
return 0;
}
最后这里想说明的是我们可以通过仿函数来控制比较方式。
- 点赞
- 收藏
- 关注作者
评论(0)