C++ : STL容器(适配器)之stack、queue剖析

news2024/11/26 0:28:45

在这里插入图片描述

STL容器适配器之stack、queue剖析

  • 一、stack、queue的接口
    • (一)stack 接口说明
    • (二)queue 接口说明
  • 二、stack、queue的模拟实现
    • (一)stack、queue是容器适配器
      • stack、queue底层默认容器--deque
        • 1、deque概念及原理
        • 2、stl中deque迭代器的实现(部分)
    • (二)stack的模拟实现
    • (三)queue的模拟实现
  • 三、优先队列
    • (一)优先队列的概念
    • (二)优先队列的接口说明
    • (三)优先队列的模拟实现
  • 四、结束语

一、stack、queue的接口

(一)stack 接口说明

  • stack()
    • 构造空的栈
  • empty()
    • 检测stack是否为空
  • size()
    • 返回stack中元素的个数
  • top()
    • 返回栈顶元素的引用
  • push()
    • 将元素val压入stack中
  • pop()
    • 将stack中尾部的元素弹出

(二)queue 接口说明

  • empty:
    • 检测队列是否为空
  • size:
    • 返回队列中有效元素的个数
  • front:
    • 返回队头元素的引用
  • back:
    • 返回队尾元素的引用
  • push_back:
    • 在队列尾部入队列
  • pop_front:
    • 在队列头部出队列

二、stack、queue的模拟实现

(一)stack、queue是容器适配器

虽然stackqueue中也可以存放元素,但在STL中并没有将其划分在容器的行列,而是将其称为容器适配器,这是因为stackqueue只是对其他容器的接口进行了包装,STL中stackqueue默认使用deque.

stack、queue底层默认容器–deque

1、deque概念及原理

deque(双端队列):可以在头尾两端进行插入和删除操作,且时间复杂度为O(1),与vector比较,头插效率高,不需要搬移元素;与list比较,空间利用率比较高。

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

双端队列底层是一段假象的连续空间,实际是分段连续的,为了维护其“整体连续”以及随机访问
的假象,落在了deque的迭代器身上

2、stl中deque迭代器的实现(部分)

在这里插入图片描述
在stl源码实现中,下面截取了迭代器的部分,有很多知识值得学习。

1、普通迭代器和const迭代器实现技巧

我们知道const对象的实现就是不能修改值,因此只需要在实现迭代器时针对一下->*的返回值即可,源码库中使用两个模板参数巧妙的解决这个问题。

2、非类型模板参数

在模板进阶中我们会讲到非类型模板参数的使用,使用size_t作为参数相当于一个宏的使用。
template <class T, class Ref, class Ptr, size_t BufSiz>

3、重载的复用

先实现重载符号 += 接着的 +、-、-=都采用了复用的方式,使得代码更简洁。
在实现++、–时,先实现前置++,前置–,再实现后置++,后置–,这里也可以复用

#pragma once
template <class T, class Ref, class Ptr, size_t BufSiz>
struct __deque_iterator {
	typedef __deque_iterator<T, T&, T*, BufSiz>             iterator;
	typedef __deque_iterator<T, const T&, const T*, BufSiz> const_iterator;

	typedef T value_type;
	typedef Ptr pointer;
	typedef Ref reference;
	typedef T** map_pointer;
	typedef ptrdiff_t difference_type;
	typedef __deque_iterator self;

	//构造函数
	//有参构造
	__deque_iterator(T* x, map_pointer y)
		: cur(x), first(*y), last(*y + buffer_size()), node(y) {}
	//默认构造
	__deque_iterator() : cur(0), first(0), last(0), node(0) {}
	//拷贝构造
	__deque_iterator(const iterator& x)
		: cur(x.cur), first(x.first), last(x.last), node(x.node) {}

	//更新结点信息
	void set_node(map_pointer new_node) {
		node = new_node;
		first = *new_node;
		last = first + difference_type(buffer_size());
	}

	//运算符重载
	reference operator*() const { return *cur; }
	pointer operator->() const { return &(operator*()); }
	self& operator++() {
		++cur;
		if (cur == last) {
			set_node(node + 1);
			cur = first;
		}
		return *this;
	}

	self operator++(int) {
		self tmp = *this;
		++*this;
		return tmp;
	}

	self& operator--() {
		if (cur == first) {
			set_node(node - 1);
			cur = last;
		}
		--cur;
		return *this;
	}

	self operator--(int) {
		self tmp = *this;
		--*this;
		return tmp;
	}

	self& operator+=(difference_type n) {
		difference_type offset = n + (cur - first);
		if (offset >= 0 && offset < difference_type(buffer_size()))
			cur += n;
		else {
			difference_type node_offset =
				offset > 0 ? offset / difference_type(buffer_size())
				: -difference_type((-offset - 1) / buffer_size()) - 1;
			set_node(node + node_offset);
			cur = first + (offset - node_offset * difference_type(buffer_size()));
		}
		return *this;
	}

	self operator+(difference_type n) const {
		self tmp = *this;
		return tmp += n;
	}

	self& operator-=(difference_type n) { return *this += -n; }

	self operator-(difference_type n) const {
		self tmp = *this;
		return tmp -= n;
	}

	reference operator[](difference_type n) const { return *(*this + n); }

	bool operator==(const self& x) const { return cur == x.cur; }
	bool operator!=(const self& x) const { return !(*this == x); }
	bool operator<(const self& x) const {
		return (node == x.node) ? (cur < x.cur) : (node < x.node);
	}


	//成员变量
private:
	T* cur;
	T* first;
	T* last;
	map_pointer node;
};

(二)stack的模拟实现

通过stack的实现可以看出,stack的实现是基于deque栈的实现就是将双端队列进行包装,这个过程就像是deque是交流电,而stack就是这个插头,为用户提供需要的接口。

#pragma once
#include<vector>
#include<list>
#include<deque>
using namespace std;

namespace wgm {
	template<class T, class Container = deque<T>>
	class stack {
	public:
		void push(const T& val) {
			_con.push_back(val);
		}

		void pop() {
			_con.pop_back();
		}

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

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


		const T& top()  const
		{
			return _con.back();
		}

	private:
		Container _con;
	};
}

(三)queue的模拟实现

stack类似,在它的参数列表中也有一个参数类型Container(容器),它也存在默认参数deque。这里的参数不能传入vector,因为vector不支持头部出元素的pop_front操作。

#pragma once
#include<vector>
#include<list>
#include<deque>
using namespace std;

namespace wgm {
	template<class T, class Container = deque<T>>
	class queue {
	public:
		void push(const T& val) {
			_con.push_back(val);
		}

		void pop() {
			_con.pop_front();
		}

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

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

		const T& front() const
		{
			return _con.front();
		}

		const T& back() const
		{
			return _con.back();
		}

	private:
		Container _con;
	};
}

三、优先队列

(一)优先队列的概念

优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大(小)的。实际上,这就和之前学过的数据结构堆的性质一样。

(二)优先队列的接口说明

  • empty():
    • 检测容器是否为空
  • size():
    • 返回容器中有效元素个数
  • front():
    • 返回容器中第一个元素的引用
  • push_back():
    • 在容器尾部插入元素
  • pop_back():
    • 删除容器尾部元素

(三)优先队列的模拟实现

#pragma once
#include<vector>
#include<iostream>
using namespace std;

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

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

	template<class T , class Container = vector<T>, class Compare = less<T>>
	class priority_queue {
	public:
#define FATHER(i) (((i) - 1) / 2)
#define LEFT(i) (((i) * 2) + 1)
#define RIGHT(i) (((i) * 2) + 2)
		void AdjustUp(int i)
		{
			Compare cmp;
			while (FATHER(i) >= 0 && Compare()(_con[FATHER(i)], _con[i])) {
				swap(_con[i], _con[FATHER(i)]);
				i = FATHER(i);
			}
		}

		void AdjustDown(int i)
		{
			while (LEFT(i) < _con.size()) {
				int l = LEFT(i), r = RIGHT(i), ind = i;
				Compare cmp;
				if (cmp(_con[ind], _con[LEFT(i)])) ind = LEFT(i);
				if (RIGHT(i) < _con.size() && cmp(_con[ind], _con[RIGHT(i)])) ind = RIGHT(i);
				if (ind == i) break;
				swap(_con[i], _con[ind]);
				i = ind;
			}
		}

		void push(const T& val)
		{
			_con.push_back(val);
			AdjustUp(_con.size() - 1);
		}

		void pop()
		{
			swap(_con[0], _con[_con.size() - 1]);
			_con.pop_back();
			AdjustDown(0);
		}

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

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

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

	private:
		Container _con;
	};
}

四、结束语

这个部分相对于之前学的容器要简单,只不过这个双端队列的实现源码还是挺有意思的,可以尝时着实现实现。

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

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

相关文章

排序算法.

排序算法是最常用的一种算法.它解决的主要问题是在一定的时间复杂度和空间复杂度的条件下,对n个数按照一定的顺序进行排序.排序算法主要分为四大类,即插入类,交换类,选择类和归并类,不同的排序算法的时间复杂程度和空间复杂程度差别很大. 排序算法主要有以下几种: 1.插入类排…

window下安装rust 及 vscode配置

安装 安装mingw64 &#xff08;c语言环境 选择posix-ucrt&#xff09; ucrt:通用c运行时库配置mingw64/bin的路径到环境变量中在cmd窗口中输入命令 "gcc -v" 4. 下载Rust安装程序 安装 Rust - Rust 程序设计语言 5. 配置rustup和cargo目录 &#xff08;cargo是包管…

contos7.9 部署3节点 hadoop3.4 集群 非高可用

contos7.9 部署3节点 hadoop3.4 集群 非高可用 contos7.9 部署3节点 hadoop3.4 集群 非高可用环境信息服务器角色分配服务器配置服务器配置初始化 init_server.sh配置主机名映射所有节点配置 hosts文件 配置免密登录 hadoop 安装环境配置下载安装包下载 jdk1.8hadoop3.4 分发安…

M1M2 MAC安装windows11 虚拟机的全过程

M1/M2 MAC安装windows11 虚拟机的全过程 这两天折腾了一下windows11 arm架构的虚拟机&#xff0c;将途中遇到的坑总结一下。 1、虚拟机软件&#xff1a;vmware fusion 13.6 或者 parallel 19 &#xff1f; 结论是&#xff1a;用parellel 19。 这两个软件都安装过&#xff0…

【设计模式系列】享元模式(十五)

目录 一、什么是享元模式 二、享元模式的角色 三、享元模式的典型应用场景 四、享元模式在ThreadPoolExecutor中的应用 1. 享元对象&#xff08;Flyweight&#xff09;- 工作线程&#xff08;Worker&#xff09; 2. 享元工厂&#xff08;Flyweight Factory&#xff09;- …

国产化浪潮下,高科技企业如何选择合适的国产ftp软件方案?

高科技企业在数字化转型和创新发展中&#xff0c;数据资产扮演着越来越重要的角色。在研发过程中产生的实验数据、设计文档、测试结果等&#xff0c;专利、商标、版权之类的创新成果等&#xff0c;随着信息量急剧增加和安全威胁的复杂化&#xff0c;传统的FTP软件已经不能满足这…

大模型人工智能课程全栈完整学习路径

嘿&#xff0c;朋友们&#xff0c;今天我们聊点高级的——大模型人工智能课程的全栈学习路径。不过别慌&#xff0c;虽然听起来高大上&#xff0c;但咱们慢慢来。从零开始&#xff0c;一步步带你走进这个神奇的世界。喝杯咖啡&#xff0c;穿上最舒适的拖鞋&#xff0c;准备好踏…

【CUDA】认识CUDA

目录 一、CUDA编程 二、第一个CUDA程序 三、CUDA关键字 四、device管理 4.1 初始化 4.2 Runtime API查询GPU信息 4.3 决定最佳GPU CUDA C 编程指南CUDA C在线文档&#xff1a;CUDA C 编程指南 CUDA是并行计算的平台和类C编程模型&#xff0c;能很容易的实现并行算法。只…

吾店云介绍 – 中国人的WordPress独立站和商城系统平台

经过多年在WordPress建站领域的摸索和探索&#xff0c;能轻松创建和管理各种类型网站的平台 – 吾店云建站平台诞生了。 应该说这是一个艰苦卓绝的过程&#xff0c;在中国创建一个能轻松创建和使用WordPress网站的平台并不容易&#xff0c;最主要是网络环境和托管软件的限制。…

黔院长 | 慢病快调,中医养生的奇迹之旅!

想象一下&#xff0c;自己踏上了一场奇妙的冒险之旅&#xff0c;而目的地就是健康的彼岸。在这场旅途中&#xff0c;黔院长如同一位智慧的向导&#xff0c;引领我们穿越中医养生的神秘世界&#xff0c;实现慢病快调。 黔院长&#xff0c;这个拥有着古老传承的中医世家&#xff…

JavaWeb合集23-文件上传

二十三 、 文件上传 实现效果&#xff1a;用户点击上传按钮、选择上传的头像&#xff0c;确定自动上传&#xff0c;将上传的文件保存到指定的目录中&#xff0c;并重新命名&#xff0c;生成访问链接&#xff0c;返回给前端进行回显。 1、前端实现 vue3AntDesignVue实现 <tem…

Java项目实战II基于Spring Boot的药店管理系统的设计与实现(开发文档+数据库+源码)

目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。 一、前言 随着医疗行业的快速发展和人们对健康需…

「撸一手好代码」设计模式之接口隔离原则

「撸一手好代码」设计模式之接口隔离原则 什么是接口隔离原则 接口隔离原则&#xff08;Interface Segregation Principle, ISP&#xff09;指出&#xff0c;客户端不应该依赖它不使用的接口。换句话说&#xff0c;一个类对另一个类的依赖应该建立在最小的接口上。接口的设计应…

在 WPF 中,绑定机制是如何工作的?WPF数据绑定机制解析

在WPF&#xff08;Windows Presentation Foundation&#xff09;中&#xff0c;数据绑定机制是其核心功能之一&#xff0c;广泛用于连接应用程序的UI&#xff08;用户界面&#xff09;和应用程序的业务逻辑层。数据绑定允许你将UI元素与数据源&#xff08;如对象、集合或其他数…

线性代数:Matrix2x2和Matrix3x3

今天整理自己的框架代码&#xff0c;将Matrix2x2和Matrix3x3给扩展了一下&#xff0c;发现网上unity数学计算相关挺少的&#xff0c;所以记录一下。 首先扩展Matrix2x2&#xff1a; using System.Collections; using System.Collections.Generic; using Unity.Mathemati…

字节青训-小F的永久代币卡回本计划、

目录 一、小F的永久代币卡回本计划 问题描述 测试样例 解题思路&#xff1a; 问题理解&#xff1a; 数学公式&#xff1a; 代码实现&#xff1a; 最终代码&#xff1a; 运行结果&#xff1a; 二、构造特定数组的逆序拼接 问题描述 测试样例 解题思路&#xff1a;…

PGMP-串串0203 项目集管理绩效域战略一致性

1.项目集管理绩效域 2.战略一致性 战略一致性包含内容商业论证BC项目集章程项目集路线图环境评估项目集风险管理策略 前期formulation sub-phaseplanning sub-phase组织的战略计划项目集风险管理策略项目集管理计划商业论证BC项目集章程项目集路线图环境评估

使用ThorUi

摘要&#xff1a; 官网 今天遇到一个老项目&#xff0c;使用的是ThorUi组件库&#xff01;之前没有用过这组件库&#xff0c;所以记录一下不同框架是使用情况&#xff01; ThorUI 是一个基于 Thorium 的 UI 框架&#xff0c;用于构建跨平台的桌面应用程序。如果你打算使用 Thor…

【activiti工作流源码集成】springboot+activiti+mysql+vue+redis工作流审批流集成整合业务绑定表单流程图会签驳回

工作流集成实际项目案例&#xff0c;demo提供 源码获取方式&#xff1a;本文末个人名片直接获取。 前言 activiti工作流引擎项目&#xff0c;企业erp、oa、hr、crm等企事业办公系统轻松落地&#xff0c;请假审批demo从流程绘制到审批结束实例。 一、项目形式 springbootvue…

【React.js】AntDesignPro左侧菜单栏栏目名称不显示的解决方案

作者&#xff1a;CSDN-PleaSure乐事 欢迎大家阅读我的博客 希望大家喜欢 使用环境&#xff1a;WebStorm 目录 问题概述 原因 解决方案 解决方法 潜在问题修改 最终效果呈现 额外内容 管理员界面路由配置 WebStorm背景更换 法一&#xff1a; 法二&#xff1a; 问题概…