【C++笔记】容器适配器及deque和仿函数

news2024/11/5 17:25:59

【C++笔记】容器适配器及deque和仿函数

🔥个人主页大白的编程日记

🔥专栏C++笔记


文章目录

  • 【C++笔记】容器适配器及deque和仿函数
    • 前言
    • 一.容器适配器
      • 1.1什么是容器适配器
      • 1.2 STL标准库中stack和queue的底层结构
    • 二.stack
      • 2.1stack类模版
      • 2.2头文件问题
    • 三.queue
      • 3.1queue类模版
      • 3.2按需实例化
    • 四priority_queue
      • 4.1priority_queue的定义
      • 4.2仿函数
    • 五.deque
      • 5.1deque的定义
      • 5.2deque的结构
    • 后言

前言

哈喽,各位小伙伴大家好!上期我们讲了list结构剖析及其模拟实现。今天我们来讲一下dequeue和模版进阶。话不多说,我们进入正题!向大厂冲锋
在这里插入图片描述

一.容器适配器

1.1什么是容器适配器

适配器是一种设计模式(设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结),该种模式是将一个类的接口转换成客户希望的另外一个接口。


容器适配器就像我们的电流适配器一样。

容器适配器就是一种转化接口,把一种接口转化为我们需要的接口。

1.2 STL标准库中stack和queue的底层结构

虽然stack和queue中也可以存放元素,但在STL中并没有将其划分在容器的行列,而是将其称为容器适配器,这是因为stack和队列只是对其他容器的接口进行了包装,STL中stack和queue默认使用deque,比如:
如果我们需要写一个栈的类模版。我们会自己手搓一个出来。

template<class T>
class stack
{
private:
	T* ptr;
	size_t size;
	size_t capacity;
};

但是栈只需要栈顶插入和删除,也就是说只需要支持一端插入和删除即可。那我们的vector和list容器都支持一端插入和删除。所以我们可以用vector和list容器封装实现。

所以我们的栈就可以用一个容器封装实现

    //container适配转化出Stack
	template<class T, class container = vector<T>>
	class Stack
	{
	public:
	private:
		container con;
	};

这里我们container传vector就是用vector适配转化的栈,传list就是list适配转化的栈。这就是我们通过container模版参数用容器适配器模式写的一个栈。

库里的栈也是这样做的。

在这里插入图片描述

二.stack

2.1stack类模版

这里我们用容器适配器写了一个栈的类模版。
成员是container。成员函数再调用容器的接口即可实现一个先进先出的栈。
默认使用vector容器适配。

//container适配转化出Stack
template<class T, class container = vector<T>>
class Stack
{
public:
	void push(T x)
	{
		con.push_back(x);
	}
	void pop()
	{
		con.pop_back();
	}
	const T& Top() const
	{
		return con.back();
	}
	size_t size() const
	{
		return con.size();
	}
	bool empty() const
	{
		return con.empty();
	}
private:
	container con;
};

2.2头文件问题

我们自己写的文件包含在.cpp文件时尽量放在最后面。防止出现以下错误。

三.queue

3.1queue类模版

这里queue我们也是使用适配器模式。因为queue要求一端进一端出。
所以使用list容器适配更合适。也是调用对应容器的接口即可。

	//container适配转化出Queue
	template<class T, class container =list<T>>
	class Queue
	{
	public:
		void push(T x)
		{
			con.push_back(x);
		}
		void pop()
		{
			con.pop_front();
		}
		const T& front() const
		{
			return con.front();
		}
		const T& back() const
		{
			return con.back();
		}
		size_t size() const
		{
			return con.size();
		}
		bool empty() const
		{
			return con.empty();
		}
	private:
		container con;
	};

3.2按需实例化

类模版实例化是按需实例化。什么是按需实例化呢?

所以这里我们没报错,因为我们没有调用pop_front.

但当我们调用pop时就会报错。这就是因为按需实例化。

四priority_queue

4.1priority_queue的定义

priority_queue也是一个容器适配器.priority_queue也叫优先级队列
在这里插入图片描述

通过对priority_queue的底层结构就是堆,因此此处只需对对进行通用的封装即可。
堆我们用下标计算父子关系。所以priority_queue的默认容器是vector.

这里我们直接用容器封装即可。

template<class T, class container = vector<T>,class Compare =Less<T>>
class priority_queue
{
public:
	void AdjustDown( int parent)
	{
		Compare com;
		int child = parent * 2 + 1;//孩子节点
		while (child < con.size())
		{
			int tmp = child;//左右孩子中最小的孩子
			if (tmp + 1 < con.size() && com(con[tmp], con[tmp + 1]))//防止没有右孩子
			{
				tmp = child + 1;
			}//假设法
			if (com(con[parent], con[tmp]))//判断
			{
				swap(con[parent], con[tmp]);//交换
				parent = tmp;
				child = parent * 2 + 1;
			}
			else
			{
				break;//调整完毕
			}
		}
	}
	void AdjustUp(int size)
	{
		Compare com;
		int child = size - 1;//最后的节点
		while (child > 0)
		{
			int parent = (child - 1) / 2;//父亲节点
			if (com(con[parent],con[child]))//判断
			{
				swap(con[child], con[parent]);//交换
				child = parent;
			}
			else
			{
				break;//调整完成
			}
		}
	}
	void push(const T& x)
	{
		con.push_back(x);
		AdjustUp(con.size());
	}
	void pop()
	{
		swap(con[0], con[con.size() - 1]);
		con.pop_back();
		AdjustDown(0);
	}
	const T& top()
	{
		return con[0];
	}
	size_t size() const
	{
		return con.size();
	}
	bool empty() const
	{
		return con.empty();
	}
private:
	container con;
};

4.2仿函数

那我们怎么调整大堆小堆呢?
那就需要用到仿函数。
仿函数是个类。

template<class T>
struct Less
{
	int operator()(const T& x, const T& y)
	{
		return x < y;
	}
};

仿函数这个类主要重载operator()。
这个()里面传两个对象的比较。

Compare com;
if (com(con[parent],con[child]))//判断

这里看起来很像函数调用,但是实际上是operator()的调用。
所以被叫做仿函数。仿函数我们想支持各种类型的比较就可以写成类模版。

template<class T, class container = vector<T>,class Compare =Less<T>>

所以我们在priority_queue的模版参数里传一个仿函数类型就可以控制大堆小堆。

通过传不同仿函数类型,我们就能控制不同的比较逻辑
从而控制大小堆。

五.deque

5.1deque的定义

我们可以发现库的的stack和queue没有用list和vector。
而是用了一个dequeue的容器。

那deque是什么呢?

deque是vector和list的缝合怪。

deque(双端队列):是一种双开口的"连续"空间的数据结构,双开口的含义是:可以在头尾两端进行插入和删除操作,且时间复杂度为O(1),与vector比较,头插效率高,不需要搬移元素;与list比较,空间利用率比较高。

5.2deque的结构

deque并不是真正连续的空间,而是由一段段连续的小空间拼接而成的,实际deque类似于一个动态的二维数组,其底层结构如下图所示:

deque是通过一个指针数组来控制数据存储的数组。

  • 下标

  • 迭代器
    deque 迭代器结构有四个指针

】

deque借助两个迭代器维护,start就是第一个数据的迭代器,finish就是最后一个数据的迭代器。
在这里插入图片描述

  • 迭代器遍历

    可以看到库里的实现和我们的差不多

  • 头插尾插

  • 中间插入删除
    deque中间插入删除也需要挪动数据。

  • operator[]
    因为头插时第一个数组可能不满所以先用cur-first+n计算位置。
    如果小于当前数组直接+n接口。
    否则就用N去计算位置。

- 总结

后言

这就是容器适配器及deque和仿函数。大家自己好好消化。今天就分享到这!感谢各位的耐心垂阅!咱们下期见!拜拜~

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

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

相关文章

软考:中间件

中间件 中间件是一类位于操作系统软件与用户应用软件之间的计算机软件&#xff0c;它包括一组服务&#xff0c;以便于运行在一台或多台机器上的多个软件通过网络进行交互。 中间件的主要功能包括通信支持和应用支持。 通信支持为应用软件提供平台化的运行环境&#xff0c;屏蔽…

统信UOS设备驱动开发-常见问题

包含linux设备驱动开发的基础知识及统信UOS设备驱动的总体架构,常用的设备驱动开发调试优化手段及在环境搭建和代码编写过程中常见问题处理等。 文章目录 环境搭建如何编译驱动代码编写如何实现同源异构环境搭建 如何编译内核 下载并解压内核源码包,进入源码根目录,内核的编…

JS 异步 Promise、Async、await详解

目录 一、JS里的同步异步 二、Promise 1、状态 2、all()、race()、any() 3、简单案例 4、异步执行案例 5、解决异步嵌套繁琐的场景 三、async和await 1、async返回类型 2、async与await结合使用的简单案例 3、解决异步嵌套问题 4、批量请求优化 一、JS里的同步异步…

【Vue3】Vue3相比Vue2有哪些新特性?全面解析与应用指南

&#x1f9d1;‍&#x1f4bc; 一名茫茫大海中沉浮的小小程序员&#x1f36c; &#x1f449; 你的一键四连 (关注 点赞收藏评论)是我更新的最大动力❤️&#xff01; &#x1f4d1; 目录 &#x1f53d; 前言1️⃣ 响应式系统的改进2️⃣ Composition API的引入3️⃣ 更好的Type…

Vue 事件阻止 e.preventDefault();click.prevent

Vue 事件阻止 Vue 事件阻止 e.preventDefault(); click.prevent修饰符

基于vue3和elementPlus的el-tree组件,实现树结构穿梭框,支持数据回显和懒加载

一、功能 功能描述 数据双向穿梭&#xff1a;支持从左侧向右侧转移数据&#xff0c;以及从右侧向左侧转移数据。懒加载支持&#xff1a;支持懒加载数据&#xff0c;适用于大数据量的情况。多种展示形式&#xff1a;右侧列表支持以树形结构或列表形式展示。全选与反选&#xf…

leetcode-21-合并两个有序链表

题解&#xff1a; 1、初始化哑节点dum 2、 3、 代码&#xff1a; 参考&#xff1a;leetcode-88-合并两个有序数组

WPF怎么通过RestSharp向后端发请求

1.下载RestSharpNuGet包 2.请求类和响应类 public class ApiRequest {/// <summary>/// 请求地址/// </summary>public string Route { get; set; }/// <summary>/// 请求方式/// </summary>public Method Method { get; set; }/// <summary>//…

指派问题的求解

实验类型&#xff1a;◆验证性实验 ◇综合性实验 ◇设计性实验 实验目的&#xff1a;学会使用Matlab求解指派问题。 实验内容&#xff1a;利用Matlab编程实现枚举法求解指派问题。 实验例题&#xff1a;有5人分别对应完成5项工作&#xff0c;其各自的耗费如下表所示&#…

vue3 gsap 基于侦听器的动画

1、gsap实现动画 https://gsap.com/ .以上来自baidu ai 2、代码&#xff1a; 安装gsap&#xff1a;pnpm install gsap <script setup> import { ref, reactive, watch } from vue import gsap from gsapconst number ref(0) const tweened reactive({number: 0 })wat…

Flutter CustomScrollView 效果-顶栏透明与标签栏吸顶

CustomScrollView 效果 1. 关键组件 CustomScrollView, SliverOverlapAbsorber, SliverPersistentHeader 2. 关键内容 TLDR SliverOverlapAbsorber 包住 pinned为 true 的组件 可以被CustomScrollView 忽略高度。 以下的全部内容的都为了阐述上面这句话。初阶 Flutter 开发知…

江协科技STM32学习- P29 实验- 串口收发HEX数据包/文本数据包

&#x1f680;write in front&#x1f680; &#x1f50e;大家好&#xff0c;我是黄桃罐头&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流 &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd;​…

4.1 进程管理

在异步通信中&#xff0c;每个字符包含1位起始位、7位数据位和2位终止位&#xff0c;若每秒钟传送500个字符&#xff0c;则有效数据速率为&#xff08; &#xff09;。 A. 500b/s B. 700b/s C. 3500b/s D. 5000b/s 正确答案是 C。 解析 本题考查异步传输协议基础知识。 根据题目…

[进阶]集合的进阶(1)泛型

文章目录 泛型的深入泛型的细节泛型可以在很多地方定义泛型的继承和通配符总结 泛型的深入 泛型:是JDK5中引入的特性&#xff0c;可以在编译阶段约束操作的数据类型&#xff0c;并进行检查 泛型的格式:<数据类型> 注意:泛型只能引用数据类型 泛型的好处 统一了数据类型…

GB/T 28046.3-2011 道路车辆 电气及电子设备的环境条件和试验 第3部分:机械负荷(4)

写在前面 本系列文章主要讲解道路车辆电气及电子设备的环境条件和试验GB/T 28046标准的相关知识&#xff0c;希望能帮助更多的同学认识和了解GB/T 28046标准。 若有相关问题&#xff0c;欢迎评论沟通&#xff0c;共同进步。(*^▽^*) 第3部分&#xff1a;机械负荷 4.1 振动 …

【案例】旗帜飘动

开发平台&#xff1a;Unity 6.0 开发工具&#xff1a;Shader Graph 参考视频&#xff1a;Unity Shader Graph 旗帜飘动特效   一、效果图 二、Shader Graph 路线图 三、案例分析 核心思路&#xff1a;顶点偏移计算 与 顶点偏移忽略 3.1 纹理偏移 视觉上让旗帜保持动态飘动&a…

小白从零开始配置pytorch环境

一、下载ANACONDA 官方网址Anaconda Installers and Packages 笔者选择的是Anaconda3-5.3.0-Windows-x86_64.exe版本。全程安装可以手机开热点&#xff0c;会快一点。 二、查看电脑是否有显卡 1、打开任务管理器 2、查看电脑CUBA版本&#xff0c;如上篇文章所提到查看CUDA-V…

11.1 网络编程-套接字

练习&#xff1a; 使用搭建好的服务器和客户端&#xff0c;实现一个完整的注册&#xff0c;登录功能 服务器使用链表 文件IO的形式去记录账号和密码 代码实现&#xff1a; 服务器端&#xff1a; #include <myhead.h> struct Pack{char flags;char na…

基于MATLAB的战术手势识别

手势识别的研究起步于20世纪末&#xff0c;由于计算机技术的发展&#xff0c;特别是近年来虚拟现实技术的发展&#xff0c;手势识别的研究也到达一个新的高度。熵分析法是韩国的李金石、李振恩等人通过从背景复杂的视频数据中分割出人的手势形状&#xff0c;然后计算手型的质心…

面试题整理 1

实际参与的某公司面试&#xff0c;总结了遇到的值得整理记录的面试题。 目录 相对路径 正序判断 倒序判断 输出部门负责人及下级 代码实现 最终效果 科目平均分 SQL筛选 代码实现 分组错误 原因 查看版本 确认模式 设置模式 相遇洞穴 代码实现 方式一&#xf…