本文主要介绍
一、仿函数
1.1 仿函数的定义
所谓的仿函数(functor),是通过重载()
运算符模拟函数形为的类。
因此,这里需要明确两点:
- 仿函数不是函数,它是个类;
- 仿函数重载了()运算符,使得它的对你可以像函数那样子调用(代码的形式好像是在调用函数)。(C语言中就是函数指针)
1.2 普通仿函数
struct Less
{
bool operator()(int x,int y)
{
return x < y;
}
};
struct Greater
{
bool operator()(int x,int y)
{
return x > y;
}
};
int main()
{
// Less就叫仿函数类型 less就叫函数对象
Less less;
cout << less(1, 2) << endl;
Greater gt;
cout << gt(1, 2) << endl;
cout << gt.operator()(1,2) << endl;//两者等价
return 0;
}
为了适应更多的类型可以加入模板
//仿函数
template<class T>
struct Less
{
bool operator()(const T& x,const T& y)const
{
return x < y;
}
};
template<class T>
struct Greater
{
bool operator()(const T& x, const T& y)const
{
return x > y;
}
};
int main()
{
// Less就叫仿函数类型 less就叫函数对象
Less<int> less;
cout << less(1, 2) << endl;
Greater<int> gt;
cout << gt(1, 2) << endl;
cout << gt.operator()(1,2) << endl;
cout << Greater<double>()(3.14, 8.9) << endl;// 可以用匿名对象
return 0;
}
1.3 需要自己实现仿函数
如果在priority_queue中放自定义类型的数据,用户需要在自定义类型中提供<或者>的重载
class Date
{
public:
Date(int year = 1900, 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);
}
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;
return _cout;
}
void test_priority_queue2()
{
//priority_queue<Date> pq;
priority_queue<Date,vector<Date>,greater<Date>> pq;
pq.push(Date(2022, 1, 1));
pq.push(Date(2022, 1, 2));
pq.push(Date(2022, 1, 3));
pq.push(Date(2022, 1, 4));
while (!pq.empty())
{
cout << pq.top() << " ";
pq.pop();
}
cout << endl;
}
此处我们想存一个日期类进行比较,我们如果使用默认的less或者greater,他就会去比较两个日期类对象,但是我们想要比较的是具体的日期大小。
所以我们自定义的类型中要提供<
或者 >
的重载,在进行比较时,会去调用用户提供的<或者>的重载函数
还有什么特殊情况下,需要我们自己实现仿函数吗?
如下例子:我们在priority_queue中存放自定义类型的指针,我们需要比较的是指针就引用以后的具体日期。
void test_priority_queue2()
{
priority_queue<Date*> pq;
//priority_queue<Date,vector<Date>,greater<Date>> pq;
pq.push(new Date(2022, 1, 9));
pq.push(new Date(2022, 1, 2));
pq.push(new Date(2022, 1, 3));
pq.push(new Date(2022, 1, 4));
while (!pq.empty())
{
cout << *pq.top() << " ";
pq.pop();
}
cout << endl;
}
此时的less或者greater直接取的Date里面的地址进行比较,由于new地址是堆上的空闲随机地址,故这是不可行的,需要自己实现仿函数
class Date
{
friend class MyLess;//类外拿不到成员变量,搞成友元的
public:
Date(int year = 1900, 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);
}
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;
return _cout;
}
struct MyLess
{
bool operator()(const Date* d1, const Date* d2)const
{
return *(d1) > *(d2);
}
};
void test_priority_queue2()
{
priority_queue<Date*,vector<Date*>,MyLess> pq;
//priority_queue<Date,vector<Date>,greater<Date>> pq;
pq.push(new Date(2022, 1, 9));
pq.push(new Date(2022, 1, 2));
pq.push(new Date(2022, 1, 3));
pq.push(new Date(2022, 1, 4));
while (!pq.empty())
{
cout << *pq.top() << " ";
pq.pop();
}
cout << endl;
}
总结:
如果数据类型,不支持比较,或者比较的方式,不是你想要的那么可以自己实现仿函数,按照自己想要的方式去比较,控制比较逻辑文章来源:https://www.toymoban.com/news/detail-468849.html
二、priority_queue的模拟实现
priority_queue底层是堆的结构,因此只需要对堆进行封装即可文章来源地址https://www.toymoban.com/news/detail-468849.html
#pragma once
#include <assert.h>
namespace mwq
{
template <class T>
struct Less
{
bool operator()(const T& x, const T& y) const
{
return x < y;
}
};
template <class T>
struct Greater
{
bool operator()(const T& x, const T& y) const
{
return x > y;
}
};
template <class T, class Container = vector<T>, class Compare = Less<T>> //默认是大堆
class priority_queue
{
public:
priority_queue()
:_con()
{}
template<class InputIterator>
priority_queue(InputIterator first, InputIterator last)
:_con(first, last) //相当于传迭代器区间构造vector,只对这个区间的内容建堆
{
//从最后一个孩子的开始调整建堆
for (int i = (_con.size() - 1 - 1) / 2; i >= 0; --i)
{
AdjustDown(i);
}
}
void push(const T& x)
{
_con.push_back(x);
Adjustup(_con.size() - 1);
}
void pop()
{
assert(!empty());
std::swap(_con[0], _con[_con.size() - 1]);
_con.pop_back();
AdjustDown(0);
}
T& top()
{
assert(!empty());
return _con[0];
}
int size() const
{
return _con.size();
}
bool empty() const
{
return _con.size() == 0;
}
private:
void Adjustup(size_t child)
{
size_t parent = (child - 1) / 2;
while (child > 0)
{
Compare com;
//if (_con[parent] < _con[child])
if (com(_con[parent], _con[child]))
{
std::swap(_con[parent], _con[child]);
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
void AdjustDown(size_t parent)
{
size_t child = parent * 2 + 1;
while (child < _con.size())
{
Compare com;
//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]))
{
std::swap(_con[parent], _con[child]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
Container _con;
};
void test1()
{
priority_queue<int,vector<int>,Greater<int>> pq;
pq.push(1);
pq.push(2);
pq.push(3);
pq.push(4);
pq.push(5);
pq.push(6);
while (!pq.empty())
{
cout << pq.top() << " ";
pq.pop();
}
cout << endl;
//测试 迭代去区间构造
int arr[] = { 1,6,5,8,2,7,6 };
priority_queue<int> pq2(arr, arr + sizeof(arr)/sizeof(arr[0]));
while (!pq2.empty())
{
cout << pq2.top() << " ";
pq2.pop();
}
cout << endl;
}
}
到了这里,关于《priority_queue的模拟实现》的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!