【C++】优先级队列 priority_queue,仿函数和函数对象,反向迭代器
创始人
2024-05-29 18:11:21
0

目录

1.介绍和实现

2.仿函数和函数对象

3.oj

4.反向迭代器


1.介绍和实现

他也在的头文件里

但是他的底层是堆,并不满足先入先出(不要一看到queue就先入先出)

 

他也是一个容器适配器,用vector适配的,为什么?因为他底层是一个堆,之前就说过堆这种结构就是一个顺序表

那么这个实现岂不是爽歪歪, 堆的复习在这里

直接写了,没什么新东西

namespace wrt
{template>class priority_queue{public:priority_queue(){}template priority_queue(InputIterator first, InputIterator last):_con(first,last){for (size_t i= (_con.size() - 1 - 1 )/ 2; i >=0; i--)//一个节点-1  /2  是用来算父亲节点的 {//向下调整adjust_down(i);}}void adjust_up(size_t child)  //违背祖宗...{size_t  parent = (child - 1) / 2;while (child >0){if (_con[child] > _con[parent]){swap(_con[child], _con[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}}void adjust_down(size_t parent){size_t  child = 2 * parent + 1;//假设是左孩子,并且左孩子是最大的孩子while (child < _con.size()){if (child + 1 < _con.size()&&_con[child + 1] > _con[child]  ){child ++;}//此时的child已经是最大的孩子if (_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);adjust_up(_con.size() - 1);}void pop(){swap(_con[0], _con[_con.size() - 1]);_con.pop_back();adjust_down(0);}const T& top() const{return _con[0];}bool empty() const {return _con.empty();}size_t size(){return _con.size();}private:Container _con;};void test(){priority_queue pq;pq.push(1);pq.push(4);pq.push(6);pq.push(7);while (!pq.empty()){cout << pq.top() << " ";pq.pop();}cout << endl;}
}

2.仿函数和函数对象

注意到这有一个类,其实仿函数也是一个类,仿函数类型的 对象 叫函数对象(因为他可以像函数一样使用)

namespace wrt
{templatestruct  less{bool operator()(const T& x, const T& y){return x < y;}};templatestruct greater{bool operator()(const T& x, const T& y){return x > y;}};
}

这里的less类和greater类就是两个仿函数,

 

lessFunc是仿函数less实例化对象,根据前面的定义,他叫函数对象

实例化之后我们看lessFunc()这个形式就很像函数调用有木有,所以这就是函数对象的特征:像函数一样使用 

那么仿函数存在的意义是什么?

回顾之前C里学过的比较函数,qsort最经典的 最后一个参数需要比较函数

还有快排,冒泡....我们自己写过的函数

void BubbleSort(T* a, int n)
{for (int j = 0; j < n; ++j){int exchange = 0;for (int i = 1; i < n - j; ++i){if (a[i] < a[i - 1]){swap(a[i - 1], a[i]);exchange = 1;}}if (exchange == 0){break;}}
}

 这样写就把函数写死了

但用一下仿函数

void BubbleSort(T* a, int n, Compare com)
{for (int j = 0; j < n; ++j){int exchange = 0;for (int i = 1; i < n - j; ++i){//if (a[i] < a[i - 1])if (com(a[i], a[i - 1])){swap(a[i - 1], a[i]);exchange = 1;}}if (exchange == 0){break;}}
}

写成这样我们根本不知道这个函数是升序降序

但是根据我的要求,他是可控的

 

 

所以这就是升序 

想要降序?

 这个降序就是匿名函数实现的,如果我只有这一块需要用到greater仿函数类,那就匿名函数更省事,反之还是像less仿函数那么写就好了

这个地方com类型需要是const & 吗?其实没太大必要,要不然你上面的仿函数类的运算符()重载还得写成const的,因为这个com根本不大,仿函数里面没有成员变量,所以不就是1字节

我们平时加上const& 就是为了防止参数过大,可以不需要拷贝构造一次 


 那么我们把仿函数应用在刚才写的堆里面

向上调整的比较部分可以更改,一定要注意,库里面默认就是大堆用less

less是x < y ,所以要注意顺序com(_con[parent],_con[child])   ——com(x,y)

void adjust_up(size_t child)  //违背祖宗...{Compare com;size_t  parent = (child - 1) / 2;while (child >0){if(com(_con[parent],_con[child]))//if (_con[child] > _con[parent]){swap(_con[child], _con[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}}

然后向下调整部分的比较也改一下

	void adjust_down(size_t parent){Compare com;size_t  child = 2 * parent + 1;//假设是左孩子,并且左孩子是最大的孩子while (child < _con.size()){//	if (child + 1 < _con.size() && _con[child + 1] > _con[child])if (child + 1 < _con.size() && com( _con[child],_con[child + 1]){child++;}//此时的child已经是最大的孩子//if (_con[parent] < _con[child])if (com(_con[parent], _con[child])){swap(_con[parent], _con[child]);parent = child;child = 2 * parent + 1;}else{break;}}}

运行一下发现刚刚好

 现在想实现小堆怎么搞?

实例化的时候不再使用缺省参数,缺省了就是堆的默认(大堆)

 变成这样


现在玩点花的,看一下之前写过的日期类,我们用仿函数比较日期

日期类

 

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){_cout << d._year << "-" << d._month << "-" << d._day;return _cout;}private:int _year;int _month;int _day;
};

 发现很对

 但是如果T是日期类指针

怎么不对?小堆的堆顶不是最小的日期,这个函数首先肯定没写错,并且发现每次运行的结果居然都不一样,这时候仿函数比较的就是地址,每次new的地址都是随机的,所以不一定哪个日期的地址就大/小

这个不符合我们预期,怎么办?

自己写仿函数,因为刚才的less就是自己写的,所以再造一个很轻松

struct PDateLess
{bool operator()(const Date* d1, const Date* d2){return *d1 < *d2;}
};struct PDateGreater
{bool operator()(const Date* d1, const Date* d2){return *d1 > *d2;}
};

 

这样就没问题啦,所以这也是泛型,之前的泛型都是数据类型的广泛支持,但是现在他一定程度上也影响了我们的逻辑

 但是现在的仿函数只是冰山一角,现在浅看一下,更复杂的我们以后慢慢学习


 3.oj

数组中第K大的数字

可以建小堆,或者大堆

建大堆,然后pop k-1次就可以取到第k大,这个是时间复杂度就是O(N+(k-1)*logN)

N个元素建堆是O(N),然后popk-1次就是 (k-1)*logN

class Solution {
public:int findKthLargest(vector& nums, int k) {
priority_queuepq(nums.begin(),nums.end()) ;
while(--k)
{pq.pop();
}
return pq.top();}
};

 还可以建k个数字的小堆,堆顶就是k个数中最小的,每次有更大的就进堆,然后向下调整

最后堆顶就是第k最大,时间复杂度O(k+(n-k)*logn)

k个数字建小堆,然后剩下的最坏情况每一次比较之后都可以入,就是(n-k)*logn

class Solution {
public:int findKthLargest(vector& nums, int k) {
priority_queue,greater> pq(nums.begin(),nums.begin()+k) ;
for(size_t i=k;ipq.top()){pq.pop();pq.push(nums[i]);}
}
return pq.top();}
};


4.反向迭代器

 

泛型思维去理解,这个反向迭代器肯定是用正向迭代器封装的

template
class ReverseIterator
{typedef ReverseIterator Self;public:ReverseIterator(Iterator it):_it(it){}Self& operator++(){--_it;return *this;}Self& operator--(){++_it;return *this;}bool operator!= (const Self& s) const{return _it != s._it;}private:Iterator _it;
};

 上面的函数都很简单嘛,但是*运算符重载怎么写?

下面是反向迭代器的错误理解

 正确理解大佬的思路(对称美)

正常解引用就很坑 ,需要返回前一个位置,但是我不知道数据类型,库里面的方式就是萃取,绕了很多层,但是我们还可以用之前 那个多传几个模板的思路

template 
class ReverseIterator
{typedef ReverseIterator Self;public:ReverseIterator(Iterator it):_it(it){}Ref operator*(){Iterator tmp = _it;return *(--tmp);}Ptr operator->(){return &(operator*());}Self& operator++(){--_it;return *this;}Self& operator--(){++_it;return *this;}bool operator!= (const Self& s) const{return _it != s._it;}private:Iterator _it;
};

然后list.cpp的源文件里这个反向迭代器.h一包含

这样就可以使用啦,当然在vector里面也可以同样方法使用 

 

相关内容

热门资讯

安卓系统上位机编写,基于安卓系... 你有没有想过,手机里的安卓系统其实是个大宝藏呢?它不仅能让你的生活变得丰富多彩,还能让你成为编程小达...
华为平板安卓7.1系统,探索性... 你有没有发现,最近华为平板的新款机型简直让人眼前一亮?没错,我要跟你聊聊的就是这款搭载了安卓7.1系...
鸿蒙系统安卓怎么升级,轻松实现... 你有没有发现,最近你的华为手机好像有点不一样了?没错,那就是鸿蒙系统升级的魅力!今天,就让我来带你一...
安卓引导系统的软件,架构、功能... 你有没有发现,每次打开安卓手机,那熟悉的引导系统就像一位热情的导游,带你一步步走进这个五彩斑斓的数字...
谷歌做的安卓系统,安卓系统的创... 亲爱的读者,你是否曾好奇过,那个几乎无处不在的安卓系统,究竟是由谁打造的呢?没错,就是那个改变世界的...
安卓系统总提示更新系统,体验流... 手机又闹腾了!安卓系统总提示更新系统,你是不是也和我一样,每次看到这个提示就有点头疼呢?别急,今天就...
aos是安卓系统么?,安卓系统... 你有没有想过,手机里的那个神秘的aos系统,它是不是安卓家族的一员呢?今天,就让我带你一探究竟,揭开...
诺基亚8刷安卓系统,解锁无限可... 你手中的诺基亚8是不是已经有点儿落伍了呢?别急,今天就来给你支个招,让你的老伙计焕发新生,变身安卓小...
安卓系统能不能,可以。 你有没有想过,安卓系统到底能不能?这个问题,就像是在问一个老朋友,他是不是真的懂你。安卓系统,这个陪...
安卓系统恢复误删视频,轻松找回... 手机里的视频突然不见了,是不是你也遇到了这样的尴尬情况?别急,今天就来教你如何用安卓系统恢复误删的视...
华为安卓系统的siri,华为安... 你知道吗?华为最近在安卓系统上搞了个大动作,那就是推出了自己的Siri——华为助手。这可真是让人眼前...
wp模拟安卓系统界面,畅游虚拟... 你有没有想过,在电脑上也能体验到安卓系统的流畅与便捷呢?没错,这就是今天我要跟你分享的神奇小玩意——...
安卓系统的开发团队,谷歌开发团... 你知道吗?在科技的世界里,有一个团队可是默默无闻地创造了无数奇迹,他们就是安卓系统的开发团队。这个团...
俄语流利说安卓系统,轻松掌握俄... 你有没有想过,学习一门新语言竟然可以变得如此轻松有趣?没错,我要给你安利一款神器——俄语流利说安卓系...
安卓P系统原装铃声,唤醒科技之... 你有没有发现,手机里的那些原装铃声,有时候比我们自己的手机铃声还要动听呢?尤其是安卓P系统的原装铃声...
稳定无广告安卓系统,探索稳定无... 你有没有想过,手机系统就像是我们生活的环境,有时候干净整洁,有时候却满是杂乱无章的广告?今天,我要给...
安卓系统隔离运行app,技术革... 你知道吗?在智能手机的世界里,安卓系统可是个超级明星呢!它不仅功能强大,而且兼容性极好,几乎所有的手...
佳博3120安卓系统,引领移动... 你有没有听说过佳博3120安卓系统?这款设备最近可是火得一塌糊涂呢!想象一台集成了安卓系统的打印机,...
安卓系统放音乐全屏,沉浸式听觉... 你有没有发现,用安卓手机放音乐的时候,有时候屏幕会自动全屏显示,这可真是挺有趣的。你知道吗?这个小小...
安卓子系统是win,基于Win... 你知道吗?在科技的世界里,总是充满了惊喜和未知。今天,我要给你揭秘一个你可能没听说过的秘密:安卓子系...