比较重载

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;
    }
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值