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

news2024/12/19 23:49:24



快乐的流畅:个人主页


个人专栏:《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.coloradmin.cn/o/1487896.html

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

相关文章

延迟任务基于DeyalQueue

一&#xff0c;延迟任务应用场景&#xff1f; 一般用于处理订单&#xff0c;将redis中的数据延迟存入数据库&#xff0c;实现异步存储减少DB的压力 DelayQueue是基于内存的延迟队列 二&#xff0c; 延迟任务的实现方案有很多 DelayQueue Redisson MQ 时间轮 原理 JDK自带延…

基于Keil的RTE(run time environment)配置GD32开发环境,移植FreeRTOS

前言&#xff1a; 10多年前就用STM32了&#xff0c;最近从STM32转到GD32&#xff0c;感觉国产的芯片发展是真的快&#xff0c;不但更便宜&#xff0c;还更快更好用了&#xff08;是在是受不了STM32 I2C BUSY的那个BUG&#xff09;。 先说下&#xff0c;实际上STM32的程序可以…

5 分钟配置好 Electron 应用的图标

最近在开发博客本地客户端 HexoPress&#xff0c;应用做好后&#xff0c;需要打包&#xff0c;如果不希望打包出来 App 的图标用的是 Electron 默认的星球环绕的图标&#xff0c;那么需要自己制作图标。 制作图标 首先&#xff0c;你需要给各种操作系统制作一个满足要求的图标…

Python+OpenGL三维模型显示鼠标缩放旋转平移

程序示例精选 PythonOpenGL三维模型显示鼠标缩放旋转平移 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对《PythonOpenGL三维模型显示鼠标缩放旋转平移》编写代码&#xff0c;代码整洁&#…

「MySQL」基本操作类型

&#x1f387;个人主页&#xff1a;Ice_Sugar_7 &#x1f387;所属专栏&#xff1a;数据库 &#x1f387;欢迎点赞收藏加关注哦&#xff01; 数据库的操作 创建、显示数据库 使用 create 创建一个数据库 create database goods;然后可以用 show databases 来查看已经创建的数…

mac电脑使用pyinstaller打包python脚本

pyinstaller -F template.py 出现报错"AssertionError: Executable contains code signature!" 移除签名 codesign --remove-signature /Users/f7692281/PycharmProjects/TPtestlist/transmit_v6.0.py 打包命令 pyinstaller --windowed transmit_v6.0.py pyinst…

【MATLAB】语音信号识别与处理:T1小波滤波算法去噪及谱相减算法呈现频谱

1 基本定义 T1小波滤波算法是一种基于小波变换的信号去噪算法。它可以有效地去除信号中的噪声&#xff0c;并保留信号的主要特征。该算法的主要思想是将信号分解为多个不同尺度的小波系数&#xff0c;然后通过对小波系数进行阈值处理来去除噪声。 具体来说&#xff0c;T1小波滤…

企业CRM系统选型指南 | 掌握必备功能,提升工作效率

大家好我是卡林&#xff0c;今天分享CRM系统的十大功能&#xff0c;企业CRM系统选型指南。说起CRM的功能&#xff0c;大家会联想到什么&#xff1f;数据库、商机管理或者销售漏斗&#xff0c;这些是大部分人都会联想到的功能&#xff0c;但不太全面。如线索管理、联系人管理、客…

开发苹果iOS应用后如何提交到App Store

文章目录 摘要引言正文一、选择IPA文件和通道二、设置专用密码三、上传IPA文件提交上传界面说明 总结 摘要 本文将介绍使用AppUploader工具提交iOS应用到App Store的详细步骤。通过选择IPA文件和通道、设置专用密码以及进行上传&#xff0c;开发者可以顺利完成应用的提交上传过…

【牛客面试必刷TOP101】Day25.BM38 在二叉树中找到两个节点的最近公共祖先和BM40 重建二叉树

作者简介&#xff1a;大家好&#xff0c;我是未央&#xff1b; 博客首页&#xff1a;未央.303 系列专栏&#xff1a;牛客面试必刷TOP101 每日一句&#xff1a;人的一生&#xff0c;可以有所作为的时机只有一次&#xff0c;那就是现在&#xff01;&#xff01;&#xff01;&…

LeetCode 刷题 [C++] 第279题.完全平方数

题目描述 给你一个整数 n &#xff0c;返回 和为 n 的完全平方数的最少数量 。 完全平方数是一个整数&#xff0c;其值等于另一个整数的平方&#xff1b;换句话说&#xff0c;其值等于一个整数自乘的积。例如&#xff0c;1、4、9 和 16 都是完全平方数&#xff0c;而 3 和 11…

设计模式(十五)状态模式

请直接看原文:设计模式系列 ------------------------------------------------------------------------------------------------------------------------------- 前言 建议在阅读本文前先阅读设计模式&#xff08;十一&#xff09;策略模式这篇文章&#xff0c;虽说状态…

Python 获取beckhoff数据-OPCUA

1. 背景介绍 OPC UA&#xff08;Unified Architecture&#xff0c;统一架构&#xff09;是下一代的OPC 标准&#xff0c;它是一种工业通讯协议&#xff0c;通过提供一个完整的&#xff0c;安全和可靠的跨平台的架构&#xff0c;以获取实时和历史数据和时间。OPC UA的诞生是因为…

DSP,QX320F28337,数据手册,使用手册

自研32位双核CPU 主频400MHz 单精度浮点运算FPU 三角函数运算TMU flash 1MB&#xff0c;sram 1MB 3个12位ADC&#xff0c;采样率3MSPS 3个14位ADC&#xff0c;采样率2.67MSPS 24个ePWM通道&#xff0c;16个HRPWM&#xff08;150PS&#xff09;

爬虫实战——麻省理工学院新闻

文章目录 发现宝藏一、 目标二、 浅析三、获取所有模块四、请求处理模块、版面、文章1. 分析切换页面的参数传递2. 获取共有多少页标签并遍历版面3.解析版面并保存版面信息4. 解析文章列表和文章5. 清洗文章6. 保存文章图片 五、完整代码六、效果展示 发现宝藏 前些天发现了一…

力扣周赛387

第一题 代码 package Competition.The387Competitioin;public class Demo1 {public static void main(String[] args) {}public int[] resultArray(int[] nums) {int ans[]new int[nums.length];int arr1[]new int[nums.length];int arr2[]new int[nums.length];if(nums.leng…

玩转地下管网三维建模:MagicPipe3D系统

地下管网是保障城市运行的基础设施和“生命线”。随着实景三维中国建设的推进&#xff0c;构建地下管网三维模型与地上融合的数字孪生场景&#xff0c;对于提升智慧城市管理至关重要&#xff01;针对现有三维管线建模数据差异大、建模交互弱、模型效果差、缺乏语义信息等缺陷&a…

Lua 篇(一)— 安装运行Hello World

目录 前言一、Lua 是什么&#xff1f;二、Lua和C#的区别三、安装 LuaLinux 系统上安装Mac OS X 系统上安装Window 系统上安装emmyluaRider 安装(推荐) 四、Lua学习资料 前言 Lua 是一种轻量级的嵌入式脚本语言&#xff0c;它可以与 C 语言无缝集成&#xff0c;提供了强大的编程…

开发一套小程序所需的费用取决于多个因素

随着移动互联网的发展&#xff0c;小程序已经成为许多企业和个人推广业务和服务的重要工具。 不过&#xff0c;对于很多想要开发小程序的人来说&#xff0c;最大的疑问就是开发一套小程序要花多少钱。 这个问题的答案并不是固定的&#xff0c;因为开发一个小程序的成本取决于几…

java 实现文字转语音

1. 内网环境 windows系统 选择jacob技术实现 免费的 从官网下载最新1.20jar包和dll文件 将jar包放到maven仓库中 dll文件放到jdk的bin目录下 项目代码&#xff1a; package com.example.ybxm.controller;import com.jacob.activeX.ActiveXComponent; import com.jacob.com…