【C++容器】优先级队列 仿函数 反向迭代器

优先级队列,仿函数,反向迭代器

    • 优先级队列
      • 认识优先级队列
      • 模拟实现优先级队列
    • 浅谈仿函数
      • 仿函数的大致了解
      • 仿函数的实现
    • 反向迭代器
      • 什么是反向迭代器?
      • 反向迭代器的实现
    • 结语

优先级队列

认识优先级队列

优先级队列(priority_queue)不是队列。优先级队列是一种容器适配器,与(stack),队列(queue)具有类似的功能。

先来了解一下优先级队列有哪些功能。看下图:

在这里插入图片描述

优先级队列底层是一个(默认是大堆),第二个参数默认给的是vector,不适合list,第三个参数是仿函数函数对象)。

在这里插入图片描述

模拟实现优先级队列

大部分成员函数可以通过调用vector的成员函数来实现。

#pragma oncenamespace bit {//目前建堆默认大堆,如果想建小堆怎么办?template<class T, class Container = vector<T>>class priority_queue {private://不想让别人知道这两个函数,可以设置为私有void AdjustUp(int child){//向上调整需要和兄弟比较吗?int parent = (child - 1) / 2;while (child > 0){if (_con[child] > _con[parent]){std::swap(_con[child], _con[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}}//向下调整删除数据调用void AdjustDown(int parent){Compare com;int child = parent * 2 + 1;while (child < _con.size()){if (child + 1 < _con.size() && _con[child + 1] > _con[child]){++child;}if (com(_con[child], _con[parent])){std::swap(_con[child], _con[parent]);parent = child;child = parent * 2 + 1;}else{break;}}}public:template<class InputIterator>priority_queue(InputIterator first, InputIterator last){//传过来的迭代器可能不是有序的,所以要排序建堆。while (first != last){push(*first);++first;}}priority_queue()//会调用vector的默认构造函数{}void push(const T& val){_con.push_back(val);AdjustUp(_con.size() - 1);}const T& top() const{return _con[0];}bool empty() const{return _con.empty();}void pop(){//为什么swap不交换swap(_con[0], _con[_con.size() - 1]);//_con.size() - 1;//为什么这个程序不执行?执行了,但是size没变,只是_con.size() - 1_con.pop_back();AdjustDown(0);}void swap(priority_queue& pq){std::swap(_con, pq._con);}size_t size() const{return _con.size();}private:Container _con;};
}

如果想建小堆,但不增加代码量的冗余,有办法吗?

浅谈仿函数

仿函数的大致了解

怎么建小堆?可以增加一个参数函数指针,这个函数来控制大堆还是小堆。但是函数指针声明比较复杂,有一些声明很长,导致通用性变差。所以,仿函数就来了。

写一个类,类中写相应的方法,这个类作为参数,那么就可以调用该类中的方法了。

仿函数(函数对象)不是函数调用,只是具有函数的功能。

如下代码是对上面代码的补充与修改

仿函数的实现

#pragma oncenamespace bit {template<class T, class Container = vector<T>, class Compare = Greater<int>>class priority_queue {private://不想让别人知道这两个函数void AdjustUp(int child){Compare com;int parent = (child - 1) / 2;while (child > 0){if (com(_con[child], _con[parent])){std::swap(_con[child], _con[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}}void AdjustDown(int parent){Compare com;int child = parent * 2 + 1;while (child < _con.size()){if (child + 1 < _con.size() && com(_con[child + 1], _con[child])){++child;}if (com(_con[child], _con[parent])){std::swap(_con[child], _con[parent]);parent = child;child = parent * 2 + 1;}else{break;}}}public:template<class InputIterator>priority_queue(InputIterator first, InputIterator last){//传过来的迭代器可能不是有序的,所以要排序建堆。while (first != last){push(*first);++first;}}priority_queue()//会调用默认的构造函数{}void push(const T& val){_con.push_back(val);AdjustUp(_con.size() - 1);}const T& top() const{return _con[0];}bool empty() const{return _con.empty();}void pop(){//为什么swap不交换swap(_con[0], _con[_con.size() - 1]);//_con.size() - 1;//为什么这个程序不执行?执行了,但是size没变,只是_con.size() - 1_con.pop_back();AdjustDown(0);}void swap(priority_queue& pq){std::swap(_con, pq._con);}size_t size() const{return _con.size();}private:Container _con;};
}
template<class T>
struct Less
{
public:bool operator()(T& x, T& y){return x > y;}
};
template<class T>
struct Greater
{
public:bool operator()(T& x, T& y){return x < y;}
};

仿函数很方便,类中写许多的函数,资源的管理性不错,参数就可以只传一个类,封装性很强,灵活性很高。

反向迭代器

什么是反向迭代器?

**反向迭代器(reverse_iterator)**就是迭代器的相反。rbegin就是end,rend就是begin。

在这里插入图片描述

图中表示的rbegin,rend就是反向迭代器。

那如何实现反向迭代器呢?

反向迭代器的实现

仔细观察上面那张图,begin与rbegin,end与rend都是对称的。

·反向迭代器初始化可以调用正向迭代器的初始化

·反向迭代器++就是正向迭代器 的–,–就是正向迭代器的++。

先来看看库里面的反向迭代器是如何实现的。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

反向迭代器中有一个正向迭代器成员。++和–操作没有问题,都是调用正向迭代器的++和–函数,但是解引用(*)函数中为什么要–?

我们根据如下代码进行分析:

#include<iostream>
#include<vector>
using namespace std;int main()
{vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);vector<int>::reverse_iterator rit = v.rbegin();for (rit != v.rend()){cout << *rit << " ";++rit;}cout << endl;
}

在这里插入图片描述
)rbegin 是由 end 初始化的,所以指向最后一个元素的下一个位置。所以解引用时,rbegin 要到前一个位置,返回前一个位置的元素,rbegin不变,rbegin 和 rend 相等时循环结束。

反向迭代器的实现:

//反向迭代器可以封装一个正向迭代器,各种操作可以调用正向迭代器的函数
template<class Iterator, class Ref, class Ptr>
class ReverseIterator {
private:Iterator _it;
public:typedef ReverseIterator<Iterator, Ref, Ptr> Self;ReverseIterator()//调用正向迭代器的构造函数{}ReverseIterator(const Iterator& it):_it(it)//调用正向迭代器的拷贝构造函数{}Ref operator*()//解引用指向前一个位置的元素,本身不变。{Iterator tmp = _it;return *(--tmp);}Self& operator++()//调用正向迭代器--函数{--_it;return *this;}Self& operator--()//调用正向迭代器++函数{++_it;return *this;}bool operator!=(const Self& s)//调用正向迭代器的!=函数{return _it != s._it;}
};

结语

优先级队列(priority_queue)实现较为简单,与数据结构中的堆很相似。实现优先级队列与实现栈和队列的区别是:栈和队列可以直接复用其他容器的函数,优先级队列则需要自己加一些东西进去加工,如向下调整,仿函数等。

仿函数替换成函数指针。函数指针很麻烦,写个函数声明很长,读懂也容易绕晕。仿函数就是一个类,类中可以写许多函数,封装的很好,使用时很方便。

反向迭代器(reverse_iterator)就是理解解引用(*)的过程,写起来就是封装一个正向迭代器。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/207103.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

实现centos7与windows共享文件夹

第一步 点击设置 第二步 第三步 第四步 让共享文件夹挂载到hgfs目录下 输入如下命令: sudo vmhgfs-fuse .host:/ /mnt/hgfs -o subtypevmhgfs-fuse,allow_other完成共享

孟德尔随机化 MR入门基础-简明教程-工具变量-暴露

孟德尔随机化&#xff08;MR&#xff09;入门介绍和分章分享&#xff08;暂时不解读&#xff09; 大家好&#xff0c;孟德尔随机化大火&#xff0c;但是什么是孟德尔随机化&#xff0c;具体怎么实操呢 这没有其他教程的繁冗&#xff0c;我这篇讲最基础的孟德尔随机化的核心步…

数据治理之考评指标类

正则表达式 [] 表述一个字符应该是什么样子 [abc] 表示一个字符可以是a\b\c[a-z] 表示所有小写[a-zA-Z]所有大小写[ a-zA-Z0-9_ ] 所有大小写字母及数字和下划线 -> \w[0-9] \d\s 空格. 表示任意字符 {} 表示有多少个这样的字符 [a-z]{1,10}最少有一个&#xff0c;最多有10…

vs调试输出,不显示线程已退出

如题&#xff1a;一堆线程退出的信息&#xff0c;招人烦。 其实在vs设置里可以关闭&#xff1a; 工具-->选项-->调试-->输出窗口&#xff1a;

2018年全国硕士研究生入学统一考试管理类专业学位联考数学试题——解析版

文章目录 2018 年考研管理类联考数学真题一、问题求解&#xff08;本大题共 5 小题&#xff0c;每小题 3 分&#xff0c;共 45 分&#xff09;下列每题给出 5 个选项中&#xff0c;只有一个是符合要求的&#xff0c;请在答题卡上将所选择的字母涂黑。真题&#xff08;2018-01&a…

记录小白第一次EDUsrc:任意密码漏洞

目录 一、漏洞说明&#xff1a; 二、漏洞复现&#xff1a; 三、漏洞修复建议&#xff1a; 一、漏洞说明&#xff1a; xxxx学院身份认证系统有严重的逻辑设计缺陷&#xff1a;账户登录、手机登录、密码找回三个接口找到n个逻辑漏洞包括任意账号密码修改、信息泄露&#xff0…

【Python大数据笔记_day11_Hadoop进阶之MR和YARNZooKeeper】

MR 单词统计流程 已知文件内容: hadoop hive hadoop spark hive flink hive linux hive mysql ​ input结果: k1(行偏移量) v1(每行文本内容)0 hadoop hive hadoop spark hive 30 flink hive linux hive mysql map结果:k2(split切割后的单词) v2(拼接…

Java注解(Annotation)的基本知识

Java注解(Annotation)的基本知识 此文的目的只在于了解的注解的基本知识&#xff0c;知道注解的一些概念&#xff0c;使能够看懂注解的使用。 注解概述 Java 注解&#xff08;Annotation&#xff09;又称 Java 标注&#xff0c;使 JDK5.0 引入的一种注释机制。Java 语言中的…

基于Acconeer的A121-60GHz毫米波雷达传感器SDK移植及测距示例(STM32L496为例)

基于Acconeer的A121-60GHz毫米波雷达传感器SDK移植及测距示例&#xff08;STM32L496为例&#xff09; 工程&#xff1a; Keil工程资源 参考资料&#xff1a; A121 datasheet 1.3 A121 HAL Software Integration User Guide A121 STM32CubeIDE User Guide 官方参考示例工程&a…

2023.11.22 数据仓库2-维度建模

目录 1.数仓建设方案 2.数仓结构图,项目架构图 2.1项目架构图 2.2数仓结构图 3.建模设计 4.维度建模 什么是事实表: 什么是维度表: 数据发展模式y以及对应的模型 5.数仓建设规范 数据库划分规范 表命名规范 表字段类型规范 1.数仓建设方案 ODS: 源数据层(临时存储层) 贴…

笔记59:序列到序列学习Seq2seq

本地笔记地址&#xff1a;D:\work_file\&#xff08;4&#xff09;DeepLearning_Learning\03_个人笔记\3.循环神经网络\第9章&#xff1a;动手学深度学习~现代循环神经网络 a a a a a a a a a a a a a a a

智慧物流仓储仓库温湿度管理采集器钡铼技术远程终端RTU的使用

智慧物流仓储是当今物流行业的一个重要发展方向&#xff0c;它通过应用先进的技术和设备&#xff0c;实现对仓储环境的监控和管理。在智慧物流仓储中&#xff0c;温湿度管理是十分关键的一项工作。为了解决温湿度管理的问题&#xff0c;采集器钡铼技术远程终端RTU被广泛应用于仓…