C++STL的stack和queue(超详解)

文章目录

  • 前言
  • stack
  • 栈的题目
    • 最小栈
    • JZ31 栈的压入、弹出序列
  • stack的模拟实现
  • queue的模拟实现

前言

栈和队列这一块其实有数据结构的基础,学起来非常简单。

stack

在这里插入图片描述
栈的成员函数就这么写,除了emplace其他都已经非常熟悉了。

stack没有迭代器吗?
没有,因为栈已经不是容器了,它是容器适配器。给它一个迭代器还能保证先进先出这些吗?不能。

stack跟我们之前学的list其实很不太一样。
在这里插入图片描述
模板参数不同。
在这里插入图片描述

先快速用一下stack,让它跑起来。

void test_stack()
{
  stack<int> st;
	st.push(1);
	st.push(2);
	st.push(3);
	st.push(4);

	while (!st.empty())
	{
		cout << st.top() << " ";
		st.pop();
	}
	cout << endl;
}

在这里插入图片描述

栈的题目

最小栈

接下来我们做题来加深一下对stack的理解。
最小栈

在这里插入图片描述

思路

首先定义两个栈,一个栈是正常的栈,实现正常的操作。
我们用另一个栈是最小栈,来实现O(1)检索到最小元素的栈。

这里要不要写那4个默认成员函数?
在这里插入图片描述
不用。

push
如果是空栈或者需要push的数据小于最小栈栈顶元素,我们就push.否则最小栈不做处理。
在这里插入图片描述

注意,如果需要push的数据等于栈顶元素也要push,否则pop的时候会把最小值也pop掉

pop
如果最小栈的栈顶元素和正常栈的栈顶元素相等我们就pop

class MinStack {
public:
//不用写
    MinStack() {
       
    }
    void push(int val) {
        _st.push(val);
        if (_minst.empty() || val <= _minst.top())
        {
            _minst.push(val);
        }
    }
    void pop() {
        if (_minst.top() == _st.top())
        {
            _minst.pop();
        }
        _st.pop();
    }
    int top() {
        return _st.top();
    }
    int getMin() {
        return _minst.top();
    }
private:
    stack<int> _st;
    stack<int> _minst;
};

优化
在这里插入图片描述
如果是这样那不是很浪费。

可以这样优化,每个地方不是存一个值而是存一个结构。
在这里插入图片描述
给大家看一下结构,具体实现就先不实现了。

stack<int> _st;
struct Data
{
	int _val;
	int _count;
}
stack<Date> _minst;

这就是模板的好处,如果没有模板,那自己还需要再写一个栈。

JZ31 栈的压入、弹出序列

栈的压入、弹出序列
在这里插入图片描述
在这里插入图片描述
这道题稍有不慎就会写的很复杂,如果想清楚了也挺简单的。

在这里插入图片描述
不匹配的一种情况
在这里插入图片描述

思路
这道题有很多种思路,最简单的就是用一个栈模拟入栈出栈的过程。
如果能模拟出来就匹配了,如果模拟不出来就不行。

所以我们的重点在于模拟这个栈。

先要第一个出4,那就入数据1234。只要不匹配就入数据。
在这里插入图片描述

下一个出5,不匹配继续入
在这里插入图片描述
再看下一个要出的数据是不是栈顶的元素,是就直接出。
在这里插入图片描述
如果能把入栈序列走完,出栈序列也走完,那就匹配了。

在这里插入图片描述
以pushi为主要的,因为popi不一定能走到结尾。
第一步,入栈
第二步,判断是否要出栈(注意不一定只出一次)

在这里插入图片描述

凡是这样写一定要小心,栈出了一个,然后栈空了。

空栈调用会报错。

怎么样匹配?
两种方式
1.popi走到尾了
2.栈为空
在这里插入图片描述

stack的模拟实现

栈的实现有两种方式。
1.数组栈,尾部当作栈顶。
2.链表栈,头部当作栈顶。
数组栈更有优势一点。

传统的写法,无非就是搞一个数组,不够了就扩容。
我们这里用一个适配器的玩法。
在这里插入图片描述

适配器的本质是什么?
现实生活中,我们的充电头也叫电源适配器。电源适配器是干嘛的?是生产电源的吗?
其实是用来变压的。
所以适配器的本质是用来转换的,把原来的东西给转换过来。

容器适配器,它不是自己存储数据,它是把已有的东西进行转换。

我们要实现一个顺序栈,链表栈,我们需要自己写吗?
我们可以拿一个已有的容器封装,这样写起来更简单。
在这里插入图片描述
但是这还不是适配,还要转换。
再增加一个模板参数,Container,他具体是啥我也不知道,但是它肯定是符合我们要求的容器。
在这里插入图片描述

要实现顺序栈,传vector.
要实现链表栈,传list.

namespace but
{
	
	template<class T, class Container>
	class stack
	{
	public:
		void push(const T& x)
		{
			_con.push_back(x);
		}

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

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

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

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

	private:
		//vector<T> _v;
		Container _con;
	};

	void test_stack()
	{
	
		stack<int, vector<int>> st;//顺序栈
		//stack<int, list<int>> st;//链式栈
		//stack<int> st //缺省类型
		st.push(1);
		st.push(2);
		st.push(3);
		st.push(4);

		while (!st.empty())
		{
			cout << st.top() << " ";
			st.pop();
		}
		cout << endl;
	}
}

还可以给缺省类型。

template<class T, class Container= vector<T>>

函数传参如果不从右往左会有歧义。
在这里插入图片描述
假设传两个参数,你就不知道传给谁了。

queue的模拟实现

快速手搓。

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

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

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

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

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

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

	private:
		Container _con;
	};

	void test_queue()
	{
		queue<int> q;
		q.push(1);
		q.push(2);
		q.push(3);
		q.push(4);

		while (!q.empty())
		{
			cout << q.front() << " ";
			q.pop();
		}
		cout << endl;
		
	}
}

队列还能不能用vector适配?
队列要头插尾删,vector不支持头删。如果强行用erase,效率有点低。

在实现队列的头文件里没有包括vector和list为什么还能用?
如果编译它是会报错的,但是编译器不编译它。.h是不会被编译的,它是在包含的地方展开,然后编译器向上找。
在这里插入图片描述
这样写就不行了
在这里插入图片描述

为什么?
因为c和c++编译的时候都有一个特点,他不会在整个文件里面找。一展开像上去找,找不到vector,因为vector在std里面,又没有指定std.

在命名空间里只有指定或者展开才能找到。

从string开始,只写.h,不写cpp,为什么?
从规范角度来说肯定要写的,模板不能这么写,这样写出来是有问题的。
你可以尝试用声明和定义分离写一下stack。
在这里插入图片描述
为什么又找不到vector?
stack.cpp这里展开.h,又找不到vector.
在这里插入图片描述

声明和定义分离会导致很多问题,他会导致链接错误。链接错误就是找不到定义。
模板不能声明和定义分离。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

10个前端开发不容错过的工具网站

作为开发人员&#xff0c;我们经常寻找合适的工具和资源来帮助日常开发工作。但是很多好用的工具网站尤其是国外的网站很多人都错过了。 这里我整理了一份包含 10 个网站的列表&#xff0c;这些网站或许可以帮助到作为前端开发者的你。 1、MDN Web 文档 MDN文档无疑是 Web 开…

【Linux】锁的简单封装以及原理解析

文章目录 一、锁的原理过程1&#xff1a;过程2过程3过程4 二、 锁的简单封装1.LockGuard.hpp2.使用1.正常锁的使用2.使用封装后的 总结 一、锁的原理 为了实现互斥锁操作,大多数体系结构都提供了swap或exchange指令,该指令的作用是把寄存器和内存单元的数据相交换,由于只有一条…

让艺术触手可及!实时云渲染赋能真浪数字艺术馆首展

2023年5月18日&#xff0c;由真浪数字艺术和EZVR联合打造的真浪数字艺术馆首展–「破界交织」让艺术更自由&#xff0c;正式与大家相见。此次展览分为五个主题展馆&#xff0c;汇聚了来自全球各领域的19位青年数字艺术家一同探讨虚实共生、人机共生和万物共生的艺术创作。 真浪…

低代码开发与传统软件开发:未来趋势与竞争格局

近年来&#xff0c;低代码开发平台的快速发展引起了各行各业的广泛关注。低代码开发平台简化了软件开发的复杂性&#xff0c;提供了更快速、更灵活的开发方式。于是&#xff0c;许多人开始产生一个疑问&#xff1a;未来低代码开发是否会取代传统软件开发&#xff1f;今天这篇文…

【网络编程之初出茅庐】

前言&#xff1a;本章主要先讲解一些基本的网络知识&#xff0c;先把基本的知识用起来&#xff0c;后续会更深入的讲解底层原理。 网络编程的概念 网络编程&#xff0c;指网络上的主机&#xff0c;通过不同的进程&#xff0c;以编程的方式实现网络通信&#xff08;或称为网络数…

处理获取当前日期---------------年月日//时分秒

当前时间&#xff0c;先分组匹配&#xff0c;以数组下标索引匹配定义的汉字进行替换 处理日期方法 /* 日期格式化 */ const formatTime function formatTime(time, template) {if (typeof time ! "string") {time new Date().toLocaleString(zh-CN, { hour12: fal…

【学习笔记】Linux(基础知识)

第1章 Linux概况 1.1 Linux起源 四个重要的支柱: ①Unix操作系统; ②Minix操作系统; ③GNU计划; ④Internet网络。 1. Unix操作系统 UNIX的诞生 1971年,用汇编语言首先开发成功16位UNIX系统 1973年,用C语言重写了UNIX系统 创始人:Ken Thompson & Dennis Ritch…

phpstudy搭建WordPress教程

一、phpstudy新建配置WordPress 打开phpstudy&#xff0c;启动Apache&#xff08;或者Nginx&#xff09;和MySQL服务 来到数据库部分&#xff0c;点击[创建数据库]&#xff0c;填写新建数据库的名称&#xff0c;用户名以及密码&#xff0c;完成后点击确认 来到网站部分&#x…

mysql更新某个字段=这个字段+字符串

当我们像c#中用拼接执行sql语句时&#xff0c;如下&#xff1a; UPDATE abpusers set UserNameqyUserName where UserNameqy-wh 会出现以下错误&#xff1a; 在mysql中通过concat函数来实现 UPDATE abpusers set UserNameCONCAT(qy_,UserName) where UserNameqy-wh

逆向思考 C. Fence Painting

Problem - 1481C - Codeforces 思路&#xff1a;逆序考虑&#xff0c;因为每一块木板都是被最后一次粉刷所决定的。 从后往前开始&#xff0c;对于 c i c_i ci​来说&#xff0c; 如果这个颜色还有没有涂的木板&#xff0c;那么涂到其中一个木板即可如果这个颜色下没有未涂的…

“公益向善”|邦邦机器人积极传递企业责任感

2023年12月4日&#xff0c;由中山市场监督管理所党支部主办的“公益向善 支援接力 宪法在心中”主题活动在中山幸福里举办&#xff0c;邦邦机器人作为捐赠单位&#xff0c;用创新技术及产品赋能大众及公益&#xff0c;积极传递企业责任感&#xff0c;点亮向善之路。 邦邦机器人…

汽车电子 -- 时间同步

时间同步有两种形式&#xff0c;一种是NTP的网络校准时间&#xff0c;一种是可以CAN通信的时间同步。 一、NTP时间同步 参看&#xff1a;什么是NTP&#xff1f; 参看&#xff1a;NTP协议详解及C语言实现 网络时间协议NTP&#xff08;Network Time Protocol&#xff09;是TC…

搭建消息时光机:深入探究RabbitMQ_recent_history_exchange在Spring Boot中的应用【RabbitMQ实战 二】

&#x1f38f;&#xff1a;你只管努力&#xff0c;剩下的交给时间 &#x1f3e0; &#xff1a;小破站 搭建消息时光机&#xff1a;深入探究RabbitMQ_recent_history_exchange在Spring Boot中的应用 引言前言第一&#xff1a;开启插件支持第二&#xff1a;springboot整合第三&am…

js 转换为数组并返回(Array.of())

Array提供了方法直接将一组值转换为数组并返回 Array.of()方法 Array.of(1,2,3) 结果

哈工大《软件工程专业导论》复习指南

哈工大软件工程专业导论复习指南 文章目录 哈工大软件工程专业导论复习指南前言引言——软件工程专业导论课程引言第一章 软件工程专业初步认知第二章 软件体系结构与生命周期第三章 软件需求工程第四章 软件设计与实现第五章 软件质量与软件工程管理第六章 软件工程教育与职业…

Python码上行动系列丛书(由北京大学出版社出版)

前言 Python码上行动系列丛书火热来袭&#x1f4a5;&#x1f4a5;&#x1f4a5; 三册在手&#xff0c;Python全掌握&#xff01;无论是初学者还是进阶玩家&#xff0c;我们都有你想要的&#xff01; 让ChatGPT带你轻松入门Python编程&#xff0c;享受编程带来的乐趣&#xff0…

MATLAB——二维小波的单层分解

%% 学习目标&#xff1a;二维小波的单层分解 %% 二维小波适合图像处理和分析&#xff0c;将图像分解为4个图像 两个维度 低通&#xff0c;高通 clear all; close all; load woman.mat; %% which woman.mat Yind2gray(X,map); %将索引图像转换为灰度图像 [c…

C51--小车——L9110s电机驱动模块

电机模块开发&#xff1a; L9110s&#xff1a; 接通VCC&#xff0c;GND 模块电源指示灯亮。 IA1输入高电平&#xff0c;IA1输入低电平&#xff0c;【OA1 OB1】电机正转&#xff1b; IA1输入低电平&#xff0c;IA1输入高电平&#xff0c;【OA1 OB1】电机反转&#xff1b; IA2…

跨域解决方案详解

文章目录 同源策略PostMessageWebsocket跨域资源共享&#xff08;CORS&#xff09;两种请求简单请求基本流程withCredentials 属性 需预检的请求预检请求预检请求的回应浏览器的正常请求和回应示例 Nginx反向代理Node中间件代理搭建node代理服务使用现成的node代理服务 JSONP前…

JavaEE进阶学习: SpringBoot 日志文件

1.日志有什么用 日志的主要作用是记录系统的运行状态、事件和错误信息等。具体来说&#xff0c;日志可以用于以下几个方面&#xff1a; 故障排除&#xff1a;当系统出现故障或错误时&#xff0c;日志可以帮助开发人员定位问题的具体原因和位置&#xff0c;从而更快地修复系统。…
最新文章