【C++练级之路】【Lv.10】【STL】priority_queue类和反向迭代器的模拟实现



快乐的流畅:个人主页


个人专栏:《C语言》《数据结构世界》《进击的C++》

远方有一堆篝火,在为久候之人燃烧!

文章目录

  • 一、仿函数
    • 1.1 仿函数的介绍
    • 1.2 仿函数的优势
  • 二、priority_queue
    • 2.1 push
    • 2.2 pop
    • 2.3 top
    • 2.4 size
    • 2.5 empty
  • 三、反向迭代器
    • 3.1 成员变量与默认成员函数
    • 3.2 operator*
    • 3.3 operator->
    • 3.4 operator++
    • 3.5 operator- -
    • 3.6 relational operators
  • 四、反向迭代器的适用
  • 4.1 vector
    • 4.1.1 rbegin
    • 4.1.2 rend
  • 4.2 list
    • 4.2.1 rbegin
    • 4.2.2 rend
  • 总结

一、仿函数

1.1 仿函数的介绍

仿函数,是一种特殊类型的类,它重载了()运算符,使得这个类的使用看起来像一个函数,因此它又称为函数对象

具体来说,仿函数就是将函数的特性赋予到类上,使得这个类有了类似函数的行为。

1.2 仿函数的优势

C++设计仿函数之初,其实就是想替代庞杂难懂的函数指针,将函数指针替换为简单易懂的仿函数。

这里列举两个常用的仿函数——less和greater

template<class T>
struct less
{bool operator()(const T& x, const T& y){return x < y;}
};template<class T>
struct greater
{bool operator()(const T& x, const T& y){return x > y;}
};

二、priority_queue

细节:

  1. priority_queue也是容器适配器,默认容器使用vector
  2. 其底层数据结构是,并且默认情况为大堆
    如果不了解堆,可以先看往期【数据结构】【版本2.0】【树形深渊】——二叉树入侵
  3. 为了能方便调整大小堆,增加了仿函数的模板
template<class T, class Container = vector<T>, class Compare = less<T>>
class priority_queue
{
public:
private:Container _con;
};

悄悄说一句:其实容器模板和仿函数模板位置互换,才更加合理!(平时不怎么会换默认容器,但是会经常换仿函数来控制大小堆)

2.1 push

入堆

细节:

  1. 先尾插元素
  2. 再使用向上调整算法
void push(const T& x)
{_con.push_back(x);adjust_up(_con.size() - 1);
}

向上调整算法

细节:

  • 构造一个仿函数模板对象,再利用重载的()运算符进行比较(当然,也可以使用匿名对象)
void adjust_up(int child)
{Compare com;int parent = (child - 1) / 2;while (child > 0){if (com(_con[parent], _con[child])){swap(_con[parent], _con[child]);child = parent;parent = (child - 1) / 2;}else{break;}}
}

2.2 pop

出堆

细节:

  1. 先首尾元素互换
  2. 再尾删元素
  3. 最后使用向下调整算法
void pop()
{swap(_con[0], _con[_con.size() - 1]);_con.pop_back();adjust_down(0);
}

向下调整算法

细节:

  • 构造一个仿函数模板对象,再利用重载的()运算符进行比较(当然,也可以使用匿名对象)
void adjust_down(int parent)
{Compare com;int child = parent * 2 + 1;while (child < _con.size()){if (child + 1 < _con.size() && com(_con[child], _con[child+1])){++child;}if (com(_con[parent], _con[child])){swap(_con[parent], _con[child]);parent = child;child = parent * 2 + 1;}else{break;}}
}

2.3 top

获取堆顶元素

const T& top() const
{return _con[0];
}

2.4 size

获取堆中有效元素个数

size_t size() const
{return _con.size();
}

2.5 empty

判断堆是否为空

bool empty() const
{return _con.empty();
}

三、反向迭代器

其实,反向迭代器也是一种适配器,它是根据不同容器的正向迭代器,来生成对应的反向迭代器。

同时,反向迭代器追求一种对称美,rbegin()在end(),rend()在begin()。

3.1 成员变量与默认成员函数

细节:

  1. 仍然使用struct,标明公有属性
  2. 成员变量是一个正向迭代器
  3. 提供带参构造函数(其余的默认成员函数不用显式定义,浅拷贝即可)
template<class Iterator, class Ref, class Ptr>
struct __reverse_iterator
{typedef __reverse_iterator self;Iterator _cur;__reverse_iterator(Iterator it): _cur(it){}
};

3.2 operator*

细节:

  1. 迭代器先自减,再解引用返回
  2. 返回引用,为了区别普通迭代器和const迭代器
Ref operator*()
{Iterator tmp = _cur;return *--tmp;
}

3.3 operator->

细节:

  1. 直接调用operator*(),根据不同容器的数据取地址返回
  2. 返回指针,为了区别普通迭代器和const迭代器
Ptr operator->()
{return &(operator*());
}

3.4 operator++

细节:

  1. 反向迭代器的++,就是正向迭代器的- -
  2. 为了区分前置和后置,后置参数加上int(无实际意义,以示区分)
  3. 前置传引用返回,后置传值返回
self& operator++()
{--_cur;return *this;
}self operator++(int)
{Iterator tmp = _cur;--_cur;return tmp;
}

3.5 operator- -

细节:同上

self& operator--()
{++_cur;return *this;
}self operator--(int)
{Iterator tmp = _cur;++_cur;return tmp;
}

3.6 relational operators

bool operator!=(const self& s)
{return _cur != s._cur;
}bool operator==(const self& s)
{return _cur == s._cur;
}

四、反向迭代器的适用

4.1 vector

template<class T>
class vector
{
public:typedef T* iterator;typedef const T* const_iterator;typedef __reverse_iterator<iterator, T&, T*> reverse_iterator;typedef __reverse_iterator<iterator, const T&, const T*> const_reverse_iterator;iterator begin(){return _start;}iterator end(){return _finish;}const_iterator begin() const{return _start;}const_iterator end() const{return _finish;}//...
}

4.1.1 rbegin

reverse_iterator rbegin()
{return reverse_iterator(end());
}const_reverse_iterator rbegin() const
{return const_reverse_iterator(end());
}

4.1.2 rend

reverse_iterator rend()
{return reverse_iterator(begin());
}const_reverse_iterator rend() const
{return const_reverse_iterator(begin());
}

4.2 list

template<class T>
class list
{
public:typedef __list_node<T> node;typedef __list_iterator<T, T&, T*> iterator;typedef __list_iterator<T, const T&, const T*> const_iterator;typedef __reverse_iterator<iterator, T&, T*> reverse_iterator;typedef __reverse_iterator<iterator, const T&, const T*> const_reverse_iterator;iterator begin(){return iterator(_head->_next);}const_iterator begin() const{return const_iterator(_head->_next);}iterator end(){return iterator(_head);}const_iterator end() const{return const_iterator(_head);}//...
}

4.2.1 rbegin

reverse_iterator rbegin()
{return reverse_iterator(end());
}const_reverse_iterator rbegin() const
{return const_reverse_iterator(end());
}

4.2.2 rend

reverse_iterator rend()
{return reverse_iterator(begin());
}const_reverse_iterator rend() const
{return const_reverse_iterator(begin());
}

总结

这次学习了仿函数的概念和基本用法,对于升降序、大小堆等转换具有极大便利。同时实现了新的容器适配器——priority_queue(优先级队列),实际上就是堆。并且也完美实现了同为适配器的反向迭代器,至此,对于适配器有了更深一步的了解和运用。


真诚点赞,手有余香

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

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

相关文章

【3D Slicer】心脏CT图像分割操作保姆级教程 Cardiac CT image segmentation

心脏CT图像分割操作流程指南 1 安装3D Slicer软件2 打开文件2.1 从File->Add Data->Choose File2.2 直接拖入 3 进行分割操作4 切片填充 Fill between slices5 第二个例子6 数据保存7 打开保存后的文件 1 安装3D Slicer软件 方式二选一 1.官网&#xff1a;3D Slicer 2.百…

JNI方案说明和使用方法介绍

JNI简介 JNI(Java Native Interface)是Java编程语言中用于实现Java代码与本地(Native)代码(通常是C或C++代码)交互的机制。它允许Java应用程序调用本地代码中的功能,也可以让本地代码调用Java类和方法。JNI在Java平台上实现了Java与其他编程语言的互操作性。(即可互相…

无字母数字rce总结(自增、取反、异或、或、临时文件上传)

目录 自增 取反 异或 或 临时文件上传 自增 自 PHP 8.3.0 起&#xff0c;此功能已软弃用 在 PHP 中&#xff0c;可以递增非数字字符串。该字符串必须是字母数字 ASCII 字符串。当到达字母 Z 且递增到下个字母时&#xff0c;将进位到左侧值。例如&#xff0c;$a Z; $a;将…

C++知识点总结(23):高级模拟算法

高级模拟算法例题 一、P5661 公交换乘1. 审题2. 思路3. 参考答案 二、P1003 铺地毯1. 审题2. 参考答案 三、P1071 潜伏者1. 审题2. 思路3. 参考答案 一、P5661 公交换乘 1. 审题 2. 思路 总花费中&#xff0c;地铁是必须花费的&#xff0c;公交车可能不花钱&#xff08;坐地…

使用VisualDL进行模型训练和数据可视化

文章目录 使用VisualDL进行模型训练和数据可视化1. 环境准备1.1 安装VisualDL1.2 设置VisualDL 2. 写入数据并可视化2.1 检查训练数据2.2 跟踪模型训练2.3 评估模型训练效果 3. 启动VisualDL服务4. 总结 使用VisualDL进行模型训练和数据可视化 VisualDL是飞桨提供的一个可视化…

Java中的Object类详解

Java中的Object类详解 1. equals(Object obj)2. hashCode()3. toString()4.getClass()5.notify() 和 notifyAll()6. wait() 和 wait(long timeout)7. clone()8.finalize() Java中的 Object 类是所有类的父类&#xff0c;可以被所有Java类继承并使用。下面先看下源码&#xff1a…

google最新大语言模型gemma本地化部署

Gemma是google推出的新一代大语言模型&#xff0c;构建目标是本地化、开源、高性能。 与同类大语言模型对比&#xff0c;它不仅对硬件的依赖更小&#xff0c;性能却更高。关键是完全开源&#xff0c;使得对模型在具有行业特性的场景中&#xff0c;有了高度定制的能力。 Gemma模…

革新商务数据体验:引领市场的API商品数据接口

在当今商业环境中&#xff0c;革新商务数据体验对于维持竞争优势至关重要。API商品数据接口在这一转型过程中扮演了核心角色&#xff0c;它不仅为企业提供了实时且全面的数据访问能力&#xff0c;而且还极大地增强了数据的可操作性和决策支持功能。以下是API商品数据接口如何细…

面试数据库篇(mysql)- 12分库分表

拆分策略 垂直分库 垂直分库:以表为依据,根据业务将不同表拆分到不同库中。 特点: 按业务对数据分级管理、维护、监控、扩展在高并发下,提高磁盘IO和数据量连接数垂直分表:以字段为依据,根据字段属性将不同字段拆分到不同表中。 特点: 1,冷热数据分离 2,减少IO过渡争…

C语言入门到精通之练习42:画图,学用圆画圆形。

题目&#xff1a;画图&#xff0c;学用圆画圆形。 程序分析&#xff1a;无。 实例 #include <graphics.h> //VC6.0中是不能运行的&#xff0c;要在Turbo2.0/3.0中 int main() { int driver,mode,i; float j1,k1; driverVGA; modeVGAHI; initgraph(&d…

【Micropython基础】TCP客户端与服务器

文章目录 前言一、连接Wifi1.1 创建STA接口1.2 激活wifi接口1.3 连接WIFI1.4 判断WIFI是否连接1.5 连接WIFI总体代码 二、创建TCP 客户端2.1 创建套接字2.2 设置TCP服务器的ip地址和端口2.3 连接TCP服务器2.3 发送数据2.4 接收数据2.5 断开连接2.6 示例代码 三、TCP服务器的创建…

批量二维码的教程和优势:拓宽应用领域,提升效率与创新

随着二维码技术的不断发展&#xff0c;批量二维码在多个领域展现出了显著的优势&#xff0c;为商业和行业带来了更多便捷和创新。以下是批量二维码的一些显著优势&#xff1a; 1. 高效快速生成&#xff1a; 批量二维码一次性生成多个二维码&#xff0c;相较于逐个生成的方式&…

Linux之进程信号

目录 一、概念引入 1、生活中的信号 2、Linux中的信号 二、信号处理常见方式 三、信号的产生 1、键盘产生信号 2、系统调用接口产生信号 3、软件条件产生信号 4、硬件异常产生信号 四、信号的保存 相关概念 信号保存——三个数据结构 信号集——sigset_t 信号集操…

超简单的chatgpt-next-web部署教程!

随着AI的应用变广&#xff0c;各类AI程序已逐渐普及&#xff0c;尤其是在一些日常办公、学习等与撰写/翻译文稿密切相关的场景&#xff0c;大家都希望找到一个适合自己的稳定可靠的ChatGPT软件来使用。 ChatGPT-Next-Web就是一个很好的选择。它是一个Github上超人气的免费开源…

Docker基础教程 - 1 Docker简介

更好的阅读体验&#xff1a;点这里 &#xff08; www.doubibiji.com &#xff09; 1 Docker简介 Docker是一个强大的容器化平台&#xff0c;让你能够更轻松地构建、部署和运行应用程序。 下面我们来学习 Docker。 1.1 Docker是什么 1 现在遇到的问题 每次部署一台服务器&…

CSS 入门指南(一)CSS 概述

CSS 概述 CSS 介绍 CSS&#xff08;Cascading Style Sheets&#xff09;通常称为 CSS 样式或层叠样式表&#xff0c;是一种用来为结构化文档&#xff08;如 HTML 文档或 XML 应用&#xff09;添加样式&#xff08;字体、间距和颜色等&#xff09;以及版面的布局等外观显示样式…

《MySQL数据库》day1

文章目录 1.名词解释2.如何启动mysql数据库3.mysql常用命令4.数据库当中最基本的单元是表&#xff1a;table5.关于SQL语句的分类6.简单查询7.条件查询8.排序9.数据处理函数单行处理函数常见的有哪些&#xff1f; 10.分组函数&#xff08;多行处理函数&#xff09; 1.名词解释 …

VUE2与VUE3之间的主要区别

当谈到 Vue.js 的版本时&#xff0c;Vue 2 和 Vue 3 是最常被提及的两个版本。下面是 Vue 2 和 Vue 3 之间的一些主要区别&#xff1a; 1. 性能提升&#xff1a; Vue 3 在底层核心重写了响应式系统&#xff0c;采用了 Proxy 对象&#xff0c;大幅提高了性能。Vue 3 还引入了静…

彻底解决华为手机安装谷歌框架后出现未认证的弹窗问题

引言 本人使用华为手机通过B站等平台学习如何安装谷歌框架与商店后&#xff0c;发现安装谷歌框架后出现未认证的弹窗问题少有解决办法&#xff0c;而且容易复发&#xff0c;在借鉴相关视频后找到解决办法&#xff0c;但视频中的华谷框架需要付费才能使用&#xff0c;本文将提出…

spring注解驱动系列--自动装配

Spring利用依赖注入&#xff08;DI&#xff09;&#xff0c;完成对IOC容器中中各个组件的依赖关系赋值&#xff1b;依赖注入是spring ioc的具体体现&#xff0c;主要是通过各种注解进行属性的自动注入。 一、Autowired&#xff1a;自动注入 一、注解介绍 1、默认优先按照类型去…