当前位置: 首页 > news >正文

通过栈/队列/优先级队列/了解容器适配器,仿函数和反向迭代器

文章目录

    • 一.stack
    • 二.queue
    • 三.deque(双端队列)
    • 四.优先级队列
      • 优先级队列中的仿函数
      • 手搓优先级队列
    • 五.反向迭代器
      • 手搓反向迭代器

vector和list我们称为容器,而stack和queue却被称为容器适配器。

在这里插入图片描述

这和它们第二个模板参数有关系,可以看到stack和queue的第二个模板参数的缺省值都是deque,即双端队列容器。也就是说栈和队列都是以容器为主材料构建的,而且因为第二个参数是一个缺省值,我们不但可以使用deque构建,同样可以使用vectorlist来构建。

用已经存在的容器来封装转换成不存在的容器,这种方式就被称之为适配器模式。

有了deque提供的接口,再要实现栈和队列就会变得很简单。

一.stack

栈的特点就是后进先出,,插入和删除都是在尾部进行,栈不提供迭代器(因为栈只能访问栈顶的元素)。

#include<deque>
namespace wbm
{template <class T, class Container = deque<T>>class stack{public:bool empty()const{return _con.empty();}void push(const T&x){_con.push_back(x);}void pop(){_con.pop_back();}size_t size()const{return _con.size();}const T& top()const{return _con.back();}private:Container _con;};}

栈不但可以通过deque来封装,还可以通过vectorlist来封装,只要支持尾插尾删即可

二.queue

队列的特点是先进先出,队尾入,队头出,可以访问队头和队尾的数据,也不提供迭代器

#include<deque>namespace wbm
{template<class T,class Container=deque<T>>class queue{public:bool empty()const{return _con.empty();}void push(const T& x){_con.push_back();}void pop(){_con.pop_front();}size_t size()const{return _con.size();}const T& fornt()const{return _con.front();}const T& back()const{return _con.back();}private:Container _con;};
}

只要是支持尾插头删的容器都可以做queue的适配器,但是不建议使用数组,因为数组的头删效率太低

三.deque(双端队列)

因为vector和list都各有优缺点,因此大佬们就想是否可以创造一个容器兼具vector和list的优点又避免缺点,于是便有了双端队列deque,虽然deque的名字带着队列,但是它和队列毫无关系。

在这里插入图片描述

观察它提供的接口发现:它既支持随机访问,又支持头插头删和尾插尾删,看起来似乎确实是一个完美的容器。但如果真的那么完美,vector和list岂不是早就被淘汰了。

其实deque的底层是一个指针数组+多个buffer数组(buffer数组的大小是固定的)的组成形式;这个指针数组是一个中控数组,其中存放的元素是属于这个deque的buffer数组的地址。

第一次插入数据开辟的buffer数组的地址存放在中控数组的中间元素,如果buffer数组满了要继续尾插,则继续开辟新的buffer数组,此时第二个buffer数组的地址,存放在中控数组中间元素的下一个。如果你要头插,则开辟一个新的buffer数组,并将这个buffer数组的地址存放在中间元素的前一个。

在这里插入图片描述

deque的优点:

1.扩容代价小于vector:它只有在中控满了以后才需要扩容,并且不需要拷贝原生数据,只要将中控数组与buffer之间的映射关系拷贝下来即可。

2.因为是一段一段的空间,所以CPU高速缓存命中率高于list。

3.头尾插入删除效率都较高,并且支持随机访问

但是deque也有自己的缺点:

1.随机访问效率不如vector,它的随机访问要通过计算得到,假设每个buffer数组的大小为size,你要访问第10个元素,首先要10/size来确定这个元素在哪一个buffer数组中,再用10%size来确定这个元素在这个buffer数组中的哪个位置,所以deque也不适合排序,因为排序需要大量的随机访问。

2.中间插入删除不如list,它在中间插入删删同样需要挪动一定量的数据

3.迭代器实现复杂:它的迭代器中有四个指针,当cur==last时,说明本段空间被使用完毕++node继续去访问下一段空间,并更新firstlast

在这里插入图片描述


四.优先级队列

在这里插入图片描述

优先级队列的特点就是优先级高的先出,它也是一个容器适配器,不提供迭代器,底层是一个堆并且默认是大堆。

priority_queue<int> //小堆
priority_queue<int,vector<int>,greater<int>> //大堆

优先级队列中的仿函数

仿函数是一个函数对象,它是一个类函数的对象,要达到类函数,所以这个类中必须要重载()。优先级队列中默认是大堆,如果我们要改成小堆,除了要显示传递第三个参数以外还要更改比较大小的算法。在C语言中,为了能让qsort排序任意类型,库中使用了函数指针的办法,让使用者显示的去写一个比较函数,并将该函数的地址作为参数传递过去。仿函数的一个应用场景就类似于函数指针。

namespace wbm
{template<class T>struct less //可以使用struct,也可以使用class,它们都是类,只是默认的访问限定不同{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;}};
}
int main()
{wbm::less<int> func;//两者等价:func(1, 2)==func.operator()(1, 2);return 0;
}

手搓优先级队列

#include<vector>
#include<iostream>
namespace wbm
{template<class T>struct less //可以使用struct,也可以使用class,它们都是类,只是默认的访问限定不同{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;}};template<class T, class Container =std:: vector<T>,class Compare = less<T>>class priority_queue{private:void Adjustdown(size_t parent){Compare com;//构造一个仿函数对象size_t child = parent * 2 + 1;//先默认是左孩子大,如果右孩子更大,把孩子节点更新成右孩子while (child < _con.size()){if (child+1 < _con.size() && com(_con[child], _con[child + 1])){++child;//默认是less,也就是左孩子比右孩子小}//将孩子节点和父节点做比较if (com(_con[parent], _con[child])) {std::swap(_con[parent], _con[child]);parent = child;child = parent * 2 + 1;}else{break;}}}void Adjustup(size_t child){Compare com;size_t parent = (child - 1) / 2;while (child > 0){if (com(_con[parent], _con[child])){std::swap(_con[parent], _con[child]);child = parent;parent = (child - 1) / 2;}else{break;}}}public:priority_queue(){//要有一个默认构造,不写就会报错}//迭代器区间构造,直接构造出一个堆,使用向下调整更佳template<class InputIterator>priority_queue(InputIterator first, InputIterator last):_con(first, last)  //初始化列表,vector支持迭代器区间构造{//初始化建堆,使用向下调整,从第一个非叶子节点开始for (int i = (_con.size() - 1 - 1) / 2; i >= 0; i--){Adjustdown(i);}}void push(const T& x){_con.push_back(x);Adjustup(_con.size() - 1);}void pop(){//将首元素和末尾元素换位置删除后调整std::swap(_con.front(), _con.back());_con.pop_back();Adjustdown(0);}bool empty()const{return _con.empty();}size_t size()const{return _con.size();}const T& top()const{return _con.front();}private:Container _con;};
}

如果优先级队列中存放的是某个类的地址,又需要我们比较地址中值的优先级,那就需要使用仿函数来进行特殊处理。否则只会按照地址来比较。

五.反向迭代器

反向迭代器采用的是适配器模式,是通过正向迭代器的再封装实现的,你给它某个容器的正向迭代器,它就产生这个容器的反向迭代器,它与正向迭代器的位置是对称的并且正好相反。所以要控制反向迭代器,只需要使用运算符重载,篡改方向迭代器中++--的规则就可以。

reverse_iterator rbegin(){return reverse_iterator(end());}
reverse_iterator rend(){return reverse_iterator(begin());}

在这里插入图片描述

rbegin和end一样,指向的是最后一个元素的下一个位置,要想访问到3,要先--再访问,这个问题可以通过重载*来解决

template<class Iterator,class Ref,class Ptr>
Ref operator*()
{Iterator tmp=it;return *(--tmp);
}

手搓反向迭代器

namespace wbm
{//反向迭代器,使用正向迭代器封装template<class Iterator,class Ref,class Ptr>  //迭代器,T&/const T&,T*/const T*class ReverseIterator{typedef ReverseIterator<Iterator, Ref, Ptr> Self;public:ReverseIterator(Iterator it):_it(it){}Ref operator*(){Iterator tmp;return *(--tmp);}Ptr operator->(){return &(operator*())}Self& operator++(){--_it;return *this;}Self& operator--(){++_it;return *this;}bool operator!=(const Ref& rit)const//两个迭代器之间的比较{return _it != rit;}private:Iterator _it;//这里给的参数是一个正向迭代器};
}

相关文章:

通过栈/队列/优先级队列/了解容器适配器,仿函数和反向迭代器

文章目录 一.stack二.queue三.deque&#xff08;双端队列&#xff09;四.优先级队列优先级队列中的仿函数手搓优先级队列 五.反向迭代器手搓反向迭代器 vector和list我们称为容器&#xff0c;而stack和queue却被称为容器适配器。 这和它们第二个模板参数有关系&#xff0c;可以…...

leetcode 704. 二分查找

题目描述解题思路执行结果 leetcode 704. 二分查找 题目描述 二分查找 给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一个目标值 target &#xff0c;写一个函数搜索 nums 中的 target&#xff0c;如果目标值存在返回下标&#xff0c;否则返回 -1。 示…...

蓝牙耳机什么牌子好?500内好用的蓝牙耳机推荐

随着蓝牙耳机的受欢迎程度越来越高&#xff0c;近几年来&#xff0c;无蓝牙耳机市场呈爆发式增长&#xff0c;蓝牙耳机品牌也越来越多。那么蓝牙耳机什么牌子好&#xff1f;接下来&#xff0c;我来给大家推荐几款500内好用的蓝牙耳机&#xff0c;一起来看看吧。 一、南卡小音舱…...

设计模式 -- 中介者模式

前言 月是一轮明镜,晶莹剔透,代表着一张白纸(啥也不懂) 央是一片海洋,海乃百川,代表着一块海绵(吸纳万物) 泽是一柄利剑,千锤百炼,代表着千百锤炼(输入输出) 月央泽,学习的一种过程,从白纸->吸收各种知识->不断输入输出变成自己的内容 希望大家一起坚持这个过程,也同…...

人工智能的未来之路:语音识别的应用与挑战

随着人工智能技术的不断发展&#xff0c;语音识别已成为人工智能领域的一个重要应用。语音识别是指通过计算机对语音信号进行处理&#xff0c;将其转换为可以被计算机识别的文本或指令的过程。语音识别技术的应用范围非常广泛&#xff0c;例如智能家居、语音助手、智能客服、智…...

c++ 友元介绍

友元的目的就是让一个函数或类访问另一个函数中的私有成员 友元函数 &#xff08;1&#xff09;普通函数作为友元函数 class 类名{friend 函数返回值类型 友元函数名(形参列表);//这个形参一般是此类的对象.... } 经过以上操作后&#xff0c;友元函数就可以访问此类中的私有…...

四维轻云地理空间数据在线管理软件能够在线管理哪些数据?

四维轻云是一款地理空间数据在线管理软件&#xff0c;支持各类地理空间数据的在线管理、浏览及分享&#xff0c;用户可不受时间地点限制&#xff0c;随时随地查看各类地理空间数据。软件还具有项目管理、场景搭建、素材库等功能模块&#xff0c;支持在线协作管理&#xff0c;便…...

学习 GitHub 对我们有什么好处?

学习 GitHub 对我们有什么好处&#xff1f; 为什么要学习 GitHub&#xff0c;或者说学习 GitHub 对我们有什么好处&#xff1f; 理由一&#xff1a;GitHub 上有很多大牛出没&#xff0c;国外的咱先不说&#xff0c;就国内的像百度、腾讯、阿里之类的大公司&#xff0c;里面的很…...

java记录-反射

什么是反射 反射是一种让Java拥有一定动态性的机制&#xff0c;它允许程序在执行期间取得任何类的内部信息&#xff0c;并且直接操作任意对象的内部属性及方法 类加载 类加载后通过堆内存方法区的Class类型对象就能了解该类的结构信息&#xff0c;这个对象就像该类的一面镜子…...

这次彻底不需要账号了,无需魔法永久白嫖GPT

免费GPT 自GPT风靡以来&#xff0c;大家用的是不亦乐乎&#xff0c;你用他去解决过实际问题&#xff0c;你用他去写过代码&#xff0c;你用他去修改过bug&#xff0c;你用他去写过sql&#xff0c;你用他去画过图&#xff0c;你问过他你能想到的任何“刁钻”问题。 你&#xff…...

远程桌面连接是什么?如何开启远程桌面连接详细教程

远程桌面连接是一种非常方便的技术&#xff0c;它允许用户通过互联网在不同的计算机之间共享资源和访问数据。目前这个技术已经广泛地应用于企业、教育、医疗和其他领域&#xff0c;使得人们能够更高效地工作和学习。 这篇文章&#xff0c;我将解释远程桌面连接是什么&#xf…...

lua实战(2)

目录 值和类型子类型类型字符串type (v) 值和类型 Lua是一种动态类型语言。这意味着变量没有类型;只有价值观才有意义。该语言中没有类型定义。所有值都有自己的类型。 Lua中的所有值都是一等值。这意味着所有的值都可以存储在变量中&#xff0c;作为参数传递给其他函数&…...

UI自动化测试案例——简单的Google搜索测试

以下是一个UI自动化测试的经典案例&#xff1a; import unittest from selenium import webdriverclass GoogleSearchTest(unittest.TestCase):def setUp(self):# 创建Chrome浏览器实例self.driver webdriver.Chrome()self.driver.maximize_window() # 最大化浏览器窗口def t…...

C++之虚函数原理

对象数据和函数的存储方式 注意说的是对象。 C中的对象存储方式是 每个对象占用的存储空间只是该对象的数据部分&#xff08;虚函数指针和虚基类指针也属于数据部分&#xff09;&#xff0c;函数属于公共部分。 虚函数表 虚函数是通过虚函数表实现的。 C实现虚函数的方法是…...

Windows Information Protection(WIP)部署方案

目录 前言 一、方案准备工作 1、确定哪些数据需要保护 2、选择合适的加密方式...

细说Hibernate的缓存机制

Hibernate 的缓存机制主要包括一级缓存和二级缓存。 1. 一级缓存&#xff08;Session 缓存&#xff09;&#xff1a; 一级缓存是 Hibernate 的 Session 级别的缓存&#xff0c;与每个 Session 对象相关联。当您通过 Session 对象执行查询、保存或更新操作时&#xff0c;Hibern…...

初识C++之线程库

目录 一、C中的线程使用 二、C的线程安全问题 1. 加锁 2. 变为原子操作 3. 递归里面的锁 4. 定时锁 5. RAII的锁 三、条件变量 1. 为什么需要条件变量 2. 条件变量的使用 2.1 条件变量的相关函数 2.2 wait函数 一、C中的线程使用 线程的概念在linux中的线程栏已经…...

ChatGLM-LLaMA-chinese-insturct 学习记录(含LoRA的源码理解)

ChatGLM-LLaMA-chinese-insturct 前言一、实验记录1.1 环境配置1.2 代码理解1.2.1 LoRA 1.4 实验结果 二、总结 前言 介绍&#xff1a;探索中文instruct数据在ChatGLM, LLaMA等LLM上微调表现&#xff0c;结合PEFT等方法降低资源需求。 Github: https://github.com/27182812/Ch…...

JuiceFS-K8s部署

目录 1、部署JuiceFS-CSI驱动2、创建OBS认证信息Secret3、创建存储类4、创建PVC--PVC创建时会自动创建PV5、创建测试Pod--测试Pod创建容器内是否挂载成功 官网文档地址&#xff1a;https://juicefs.com/docs/zh/csi/introduction/ 1、部署JuiceFS-CSI驱动 部署yaml如下&#x…...

2023最新版本Camtasia电脑录屏软件好不好用?

在当今数字化时代&#xff0c;屏幕录制成为了许多用户制作教学视频、演示文稿、游戏攻略等内容的首选。本文将为您介绍几款常用的电脑录屏软件&#xff0c;包括Camtasia、OBS Studio、Bandicam等&#xff0c;并对其进行功能和用户体验方面的比较&#xff0c;同时给出10款电脑录…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…...

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…...

云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?

大家好&#xff0c;欢迎来到《云原生核心技术》系列的第七篇&#xff01; 在上一篇&#xff0c;我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在&#xff0c;我们就像一个拥有了一块崭新数字土地的农场主&#xff0c;是时…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法

树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作&#xff0c;无需更改相机配置。但是&#xff0c;一…...

遍历 Map 类型集合的方法汇总

1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...

学校招生小程序源码介绍

基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码&#xff0c;专为学校招生场景量身打造&#xff0c;功能实用且操作便捷。 从技术架构来看&#xff0c;ThinkPHP提供稳定可靠的后台服务&#xff0c;FastAdmin加速开发流程&#xff0c;UniApp则保障小程序在多端有良好的兼…...

【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表

1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...

ETLCloud可能遇到的问题有哪些?常见坑位解析

数据集成平台ETLCloud&#xff0c;主要用于支持数据的抽取&#xff08;Extract&#xff09;、转换&#xff08;Transform&#xff09;和加载&#xff08;Load&#xff09;过程。提供了一个简洁直观的界面&#xff0c;以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...

linux 下常用变更-8

1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行&#xff0c;YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID&#xff1a; YW3…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)

UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中&#xff0c;UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化&#xf…...