C++ 自定义比较方式总结
priority_queue
STL默认比较使用less(即’<'运算符),如sort(a,a+n),默认将数组按照递增的顺序来排序,priority_queue<>默认是大根堆的,每次top出最大元素。在下面例子中每次取出元素为key大的情况,这时候队首指向优先级最小的元素。
priority_queue<class Type,class Container,class Compare>
Container缺省情况以vector为容器。需要注意的是,priority_queue与queue,stack一样,是配接器不能使用迭代器,但是任然可以用迭代器来初始化。
源码 简化版本
//priority_queue
template <class T,class Sequence=vector<T>,class Compare=less<typename Sequence::value_type> >
public:
protected:
Sequence c;//底层容器
Compare comp;//元素大小比较标准
public:
priority_queue():c(){ }
explicit priority_queue(const Compare &x):c(),comp(x){}
//以下用到的make_heap,push_heap,pop_heap 都是泛型算法
template <class InputIterator >
priority_queue(InputerIterator first,InputerIterator last,const Compare &x)
:c(first,last),comp(x){make_heap(c.begin(),c.end(),comp);}
void push(const value_type& x){
__STL_TRY{
//push_heap是泛型算法,先利用底层容器的push_back()将新元素
//推入末端,再重排heap
c.push_back(x);
push_heap(c.begin(),c.end(),comp);//push_heap是泛型算法
}
__STL_UNWIND(c.clear());
}
void pop(){
__STL_TRY{
//pop_heap是泛型算法,从heap内取出一个元素,他不是真正的将元素
//取出,而是重排heap,然后再以底层容器的pop_back()取得被弹出
pop_heap(c.begin(),c.end(),comp);
c.pop_back();
}
__STL_UNWIND(c.clear());
}
};
make_heap
模板函数make_heap具有如下两个版本
template<class _RanIt>
void make_heap(_RanIt _First, _RanIt _Last);
template<class _RanIt, class _Pr>
void make_heap(_RanIt _First, _RanIt _Last, _Pr _Pred);
第一个版本采用小于操作符(operator<),第二个版本采用二元谓词(binary predicate)
建堆是进行堆排序(sort_heap)的前提,即在调用sort_heap应该先调用make_heap
用法:
template <class RandomAccessIterator, class Distance, class T, class Compare>
void __push_heap(RandomAccessIterator first, Distance holeIndex,
Distance topIndex, T value, Compare comp)
{
Distance parent = (holeIndex - 1) / 2;
//使用comp来比较
while (holeIndex > topIndex && comp(*(first + parent), value)) {
*(first + holeIndex) = *(first + parent);
holeIndex = parent;
parent = (holeIndex - 1) / 2;
}
*(first + holeIndex) = value;
}
less 源码
对于make_heap二元谓词方法,输入参数为结构体。less(上comp)是xfunctional.h中的结构体,原型如下,
template<class _Ty = void>
struct less
{ // functor for operator<
typedef _Ty first_argument_type;
typedef _Ty second_argument_type;
typedef bool result_type;
constexpr bool operator()(const _Ty& _Left, const _Ty& _Right) const
{ // apply operator< to operands
return (_Left < _Right);
}
};
less使用测试
//comp的类型为struct less<int>
auto comp = less<int>();
cout << comp(12,11) <<endl;
例子:力扣374题
给定一个非空的整数数组,返回其中出现频率前 k 高的元素。
示例 1:
给定一个非空的整数数组,返回其中出现频率前 k 高的元素。
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2:
输入: nums = [1], k = 1
输出: [1]
重载结构体
struct cmp{
bool operator()(pair<int,int> &a,pair<int,int> &b){
return a.first < b.first;
}
};
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
vector<int> res;
unordered_map<int,int> nmp;
for(int c : nums){
nmp[c] ++;
}
priority_queue<pair<int,int>,vector<pair<int,int>>,cmp> q;
for(auto &it : nmp){
q.push(make_pair(it.second,it.first));
}
for(int i = 0;i < k;i ++){
res.push_back(q.top().second);
q.pop();
}
return res;
}
};
传入比较函数
静态函数法
class Solution {
public:
static bool cmp(pair<int, int>& m, pair<int, int>& n) {
return m.first < n.first;
}
vector<int> topKFrequent(vector<int>& nums, int k) {
vector<int> res;
unordered_map<int,int> nmp;
for(int c : nums){
nmp[c] ++;
}
priority_queue<pair<int,int>,vector<pair<int,int>>,decltype(&cmp)> q(cmp);
for(auto &it : nmp){
q.push(make_pair(it.second,it.first));
}
for(int i = 0;i < k;i ++){
res.push_back(q.top().second);
q.pop();
}
return res;
}
};
传入lambda表达式
auto cmp1 = [](pair<int, int>& m, pair<int, int>& n) {
return m.first < n.first;
};
priority_queue<pair<int,int>,vector<pair<int,int>>,decltype(cmp1)> q(cmp1);
分析 以上两种传入比较函数的区别
cout << typeid(&cmp).name() << endl;
cout << typeid(cmp1).name() << endl;
/*输出:
bool (__cdecl*)(class std::vector<int,class std::allocator<int> >,class std::vector<int,class std::allocator<int> >)
class <lambda_5aa749c9c7aea2608bfde6f1a0a8d4ce>
*/
//声明函数指针方法
typedef bool (* cmp)(vector<int> &a,vector<int> &b);
重载小于运算
class MPair{
public:
int first;
int second;
MPair(int _first,int _second):first(_first),second(_second){
}
bool operator < (const MPair& a)const{
return this->first < a.first;
}
};
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
vector<int> res;
unordered_map<int,int> nmp;
for(int c : nums){
nmp[c] ++;
}
priority_queue<MPair,vector<MPair>> q;
MPair tmp(it.second,it.first);
q.push(tmp);
}
for(int i = 0;i < k;i ++){
res.push_back(q.top().second);
q.pop();
}
return res;
}
};
类推map
map的底层是红黑树,类似的,可以重载类的比较运算符,达到逆序的目的。
//利用遍历红黑树的排序性质,重载比较运算符
class MPair{
public:
int first;
int second;
MPair(int _first):first(_first){
}
bool operator < (const MPair& a)const{
return this->first > a.first;
}
};
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
vector<int> res;
unordered_map<int,int> nmp;
for(int c : nums){
nmp[c] ++;
}
map<MPair,int> mp;
for(auto &it : nmp){
MPair cc(it.second);
mp.insert(make_pair(cc,it.first));
}
int pos = 0;
auto it = mp.begin();
while(pos < k){
res.push_back(it->second);
it ++;
pos ++;
}
return res;
}
};