C++STL~~stackqueue

news/2024/9/19 10:56:46/ 标签: c++, 算法, 数据结构, stl

文章目录

    • 容器适配器
    • 一、stack&queue的概念
    • 二、stack&queue的使用
    • 三、stack&queue的练习
    • 四、总结

容器适配器

什么是适配器
适配器是一种设计模式(设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结),该种模式是将一个类的接口转换成客户希望的另外一个接口。
在这里插入图片描述
STL标准库中stack和queue的底层结构
虽然stack和queue中也可以存放元素,但在STL中并没有将其划分在容器的行列,而是将其称为容器适配器,这是因为stack和队列只是对其他容器的接口进行了包装,STL中stack和queue默认使用deque(双端队列容器)
在这里插入图片描述
在这里插入图片描述

一、stack&queue的概念

stack(栈)
概念和特点
栈是一种后进先出(Last In First Out,LIFO)的数据结构。就像一叠盘子,最后放上去的盘子最先被拿走。
在这里插入图片描述

queue(队列)
概念和特点
队列是一种先进先出(First In First Out,FIFO)的数据结构。类似于排队买东西,先到的人先得到服务。
在这里插入图片描述

二、stack&queue的使用

stack的使用
在这里插入图片描述

例如:

#include <iostream>
#include <stack>int main() {std::stack<int> s;// 向栈中压入一些元素s.push(10);s.push(20);s.push(30);// 输出栈的大小std::cout << "初始栈的大小为:" << s.size() << std::endl;// 检查栈是否为空if (!s.empty()) {std::cout << "栈不为空。" << std::endl;}// 获取栈顶元素并输出std::cout << "栈顶元素为:" << s.top() << std::endl;// 弹出栈顶元素s.pop();// 再次输出栈顶元素和栈的大小std::cout << "弹出一个元素后,栈顶元素为:" << s.top() << std::endl;std::cout << "此时栈的大小为:" << s.size() << std::endl;// 继续弹出元素直到栈为空while (!s.empty()) {s.pop();}// 检查栈是否为空if (s.empty()) {std::cout << "栈已为空。" << std::endl;}return 0;
}
}

首先向栈中压入一些元素,然后展示了如何使用size获取栈的大小,empty判断栈是否为空,top获取栈顶元素,以及pop弹出栈顶元素。
queue的使用
在这里插入图片描述

#include <iostream>
#include <queue>int main() {std::queue<int> q;// 检查初始时队列是否为空std::cout << "初始时队列是否为空:" << (q.empty()? "是" : "否") << std::endl;std::cout << "初始队列大小:" << q.size() << std::endl;// 向队列中添加元素q.push(10);q.push(20);q.push(30);// 输出队列的大小和队首、队尾元素std::cout << "添加元素后队列大小:" << q.size() << std::endl;std::cout << "队首元素(front):" << q.front() << std::endl;std::cout << "队尾元素(back):" << q.back() << std::endl;// 弹出一个元素q.pop();// 再次输出队列的大小和队首、队尾元素std::cout << "弹出一个元素后队列大小:" << q.size() << std::endl;std::cout << "队首元素(front):" << q.front() << std::endl;std::cout << "队尾元素(back):" << q.back() << std::endl;// 检查队列是否为空std::cout << "此时队列是否为空:" << (q.empty()? "是" : "否") << std::endl;return 0;
}

首先展示了初始时队列的空状态和大小,然后添加元素后展示了队列的大小、队首和队尾元素,接着弹出一个元素后再次展示相关信息,最后检查队列是否为空。需要注意的是,queue中没有top函数,因为queue的特点决定了只能从队首和队尾进行操作。

三、stack&queue的练习

1.最小栈

设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。

实现 MinStack 类: MinStack() 初始化堆栈对象。 void push(int val) 将元素val推入堆栈。 void
pop() 删除堆栈顶部的元素。 int top() 获取堆栈顶部的元素。 int getMin() 获取堆栈中的最小元素。


输入: [“MinStack”,“push”,“push”,“push”,“getMin”,“pop”,“top”,“getMin”]
[[],[-2],[0],[-3],[],[],[],[]]

输出: [null,null,null,null,-3,null,0,-2]

思路:

  • 1.首先,使用一个普通的栈来存储元素,这个栈用于实现push、pop和top操作。
  • 2.为了能够在常数时间内获取最小元素,再使用另一个栈来存储当前的最小元素。每当向主栈中压入一个元素时,如果这个元素小于等于辅助栈的栈顶元素(或者辅助栈为空时),就将这个元素也压入辅助栈。这样,辅助栈的栈顶始终是当前主栈中的最小元素。
  • 3.当执行pop操作时,如果弹出的元素等于辅助栈的栈顶元素,那么也从辅助栈中弹出这个元素,以保证辅助栈的栈顶始终是当前主栈中的最小元素。
#include <iostream>
#include <stack>class MinStack {
private:std::stack<int> mainStack;std::stack<int> minStack;
public:MinStack() {}void push(int val) {mainStack.push(val);if (minStack.empty() || val <= minStack.top()) {minStack.push(val);}}void pop() {if (mainStack.top() == minStack.top()) {minStack.pop();}mainStack.pop();}int top() {return mainStack.top();}int getMin() {return minStack.top();}
};

使用以下方式测试这个类

int main() {MinStack minStack;minStack.push(-2);minStack.push(0);minStack.push(-3);std::cout << minStack.getMin() << std::endl;minStack.pop();std::cout << minStack.top() << std::endl;std::cout << minStack.getMin() << std::endl;return 0;
}

2.栈的弹出压入序列

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。

  1. 0<=pushV.length == popV.length <=1000
  2. -1000<=pushV[i]<=1000
  3. pushV 的所有数字均不相同

示例1 输入: [1,2,3,4,5],[4,5,3,2,1] 返回值:true 说明:
可以通过push(1)=>push(2)=>push(3)=>push(4)=>pop()=>push(5)=>pop()=>pop()=>pop()=>pop() 这样的顺序得到[4,5,3,2,1]这个序列,返回true
示例2
输入:[1,2,3,4,5],[4,3,5,1,2]
返回值:false
说明:
由于是[1,2,3,4,5]的压入顺序,[4,3,5,1,2]的弹出顺序,要求4,3,5必须在1,2前压入,且1,2不能弹出,但是这样压入的顺序,1又不能在2之前弹出,所以无法形成的,返回false

思路:

  • 1.使用一个辅助栈来模拟入栈和出栈的过程。
  • 2.遍历压入序列pushV,将元素依次压入辅助栈。
  • 3.同时,遍历弹出序列popV,检查辅助栈的栈顶元素是否与当前要弹出的元素相等。如果相等,则从辅助栈弹出该元素,继续检查下一个弹出元素;如果不相等,则继续从压入序列中压入元素到辅助栈,直到辅助栈的栈顶元素与当前要弹出的元素相等或者压入序列遍历完。
  • 4.如果最终辅助栈为空,说明弹出序列是可能的,否则不可能。
#include <iostream>
#include <vector>
#include <stack>class Solution {
public:bool isPopOrder(std::vector<int> pushV, std::vector<int> popV) {std::stack<int> s;int i = 0, j = 0;while (i < pushV.size()) {s.push(pushV[i++]);while (!s.empty() && s.top() == popV[j]) {s.pop();j++;}}return s.empty();}
};

使用以下方式测试这个函数

int main() {Solution solution;std::vector<int> pushV = {1, 2, 3, 4, 5};std::vector<int> popV = {4, 5, 3, 2, 1};bool result = solution.isPopOrder(pushV, popV);std::cout << (result? "true" : "false") << std::endl;return 0;
}

3.二叉树的分层遍历**
给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。
在这里插入图片描述
思路

  • 1.使用一个队列来实现层序遍历。首先将根节点入队。
  • 2.不断循环,当队列不为空时:
    • 记录当前队列的大小size,这个大小表示当前层的节点个数。
    • 遍历当前层的所有节点,对于每个节点:
    • 取出节点的值,将其加入到结果列表中。
    • 如果该节点有左子节点,将左子节点入队。
    • 如果该节点有右子节点,将右子节点入队。
  • 3.循环结束后,就得到了二叉树的层序遍历结果。
#include <iostream>
#include <vector>
#include <queue>// 定义二叉树节点结构体
struct TreeNode {int val;TreeNode *left;TreeNode *right;TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};class Solution {
public:std::vector<std::vector<int>> levelOrder(TreeNode* root) {std::vector<std::vector<int>> result;if (!root) return result;std::queue<TreeNode*> q;q.push(root);while (!q.empty()) {int size = q.size();std::vector<int> level;for (int i = 0; i < size; i++) {TreeNode* node = q.front();q.pop();level.push_back(node->val);if (node->left) q.push(node->left);if (node->right) q.push(node->right);}result.push_back(level);}return result;}
};

使用以下方式测试这个函数

int main() {// 构建二叉树TreeNode* root = new TreeNode(3);root->left = new TreeNode(9);root->right = new TreeNode(20);root->right->left = new TreeNode(15);root->right->right = new TreeNode(7);Solution solution;std::vector<std::vector<int>> result = solution.levelOrder(root);for (const auto& level : result) {for (int val : level) {std::cout << val << " ";}std::cout << std::endl;}// 释放内存delete root->right->right;delete root->right->left;delete root->right;delete root->left;delete root;return 0;
}

四、总结

关于数据结构版本的stack&queue:数据结构~~栈和队列
栈(Stack)

  1. 后进先出原则。

  2. 主要操作包括入栈(push)和出栈(pop)。

  3. 常用于函数调用、表达式求值、括号匹配等场景。

队列(Queue)

  1. 先进先出原则。

  2. 主要操作包括入队(enqueue)和出队(dequeue)。

  3. 常用于任务调度、排队系统、广度优先搜索等。

两者都是基本的数据结构,具有不同的特点和适用场景,在程序设计中发挥着重要作用。


http://www.ppmy.cn/news/1525437.html

相关文章

Linux:开源世界的璀璨明珠

一、Linux 概述 Linux 是一种自由和开放源代码的类 Unix 操作系统&#xff0c;诞生于 1991 年&#xff0c;由芬兰大学生 Linus Torvalds 开发。它的起源离不开 Unix 家族&#xff0c;1969 年肯・汤普森设计了早期 Unix 的源头&#xff0c;到 1973 年丹尼斯・里奇等人以 C 语言…

DDoS对策是什么?详细解说DDoS攻击难以防御的理由和对策方法

攻击规模逐年增加的DDoS攻击。据相关调查介绍&#xff0c;2023年最大的攻击甚至达到了700Gbps。 为了抑制DDoS攻击的危害&#xff0c;采取适当的对策是很重要的。 特别是在网站显示花费时间或频繁出现504错误的情况下&#xff0c;可能已经受到了DDoS攻击&#xff0c;需要尽早采…

leetcode 每日一题

2398.预算内最多的机器人数目 2024年9月13日 滑动窗口单调队列&#xff1a; 题目里表述的不太清楚&#xff0c;连续工作的机器人&#xff0c;就是求满足条件的最长子数组&#xff1b;这题可以说是滑动窗口最大值的进阶版本。 关于滑动窗口不要自己想当然的写&#xff0c;是有…

什么是交换机级联?

在现代计算机网络中&#xff0c;交换机级联是一种广泛应用的技术&#xff0c;有助于提升网络的扩展性和灵活性。本文将深入探讨交换机级联相关知识&#xff0c;详细介绍其基本概念和连接配置方法&#xff0c;并对常见技术问题进行解答。 交换机级联概述 交换机级联是指通过将…

Golang | Leetcode Golang题解之第398题随机数索引

题目&#xff1a; 题解&#xff1a; type Solution []intfunc Constructor(nums []int) Solution {return nums }func (nums Solution) Pick(target int) (ans int) {cnt : 0for i, num : range nums {if num target {cnt // 第 cnt 次遇到 targetif rand.Intn(cnt) 0 {ans …

查谷歌流量什么最准确,服务商提供的工具为什么不能用?

查网站的SEO流量&#xff0c;Google Search Console是最准确的工具&#xff0c;因为这就是谷歌官方提供的工具&#xff0c;谷歌这方面没必要造假&#xff0c;GSC能直接展示你的网站在谷歌搜索中的表现&#xff0c;包括点击次数、展示次数、点击率和平均排名。因为这些数据直接来…

SQL数据库(MySQL)

一、在Ubuntu系统下安装MySQL数据库 1、更新软件源&#xff0c;在确保ubuntu系统能正常上网的情况下执行以下命令 sudo apt-get update 2、安装MySQL数据库及相关软件包 # 安装过程中设置root用户的密码 123456 sudo apt-get install mysql-server ​ # 安装访问数据库的客…

Spring-di基本使用

SpringDI 1 基础环境准备 流程如下 1.在自己的工程中建一个module用于SpringDi注入 2.导入spring相关的依赖 <dependencies><!--导入spring-context依赖--><dependency><groupId>org.springframework</groupId><artifactId>spring-cont…

深入解析 SQLSugar:从基础 CRUD 到读写分离与高级特性详解

SQLSugar 使用指南&#xff1a;从入门到进阶及高级特性详解 SQLSugar 是一款功能丰富的 .NET ORM 框架&#xff0c;它支持多种数据库、简洁的 API 和优雅的编程体验。相较于其他 ORM&#xff0c;SQLSugar 提供了很多开发者友好的功能&#xff0c;比如自动创建表结构、灵活的查…

【git】.gitignore文件:版本控制的守护者

在软件开发过程中&#xff0c;版本控制系统如 Git 扮演着至关重要的角色。然而&#xff0c;并非所有文件都应该被纳入版本控制。这就是 .gitignore 文件发挥作用的地方。本文将深入探讨 .gitignore 的重要性&#xff0c;解释它如何影响补丁应用&#xff0c;并提供常用的 .gitig…

【Unity学习心得】如何制作俯视角射击游戏

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、导入素材二、制作流程 1.制作地图2.实现人物动画和移动脚本3.制作单例模式和对象池4.制作手枪pistol和子弹bullet和子弹壳bulletShell5.制作散弹枪shotgun总…

EmguCV学习笔记 C# 11.6 图像分割

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 EmguCV是一个基于OpenCV的开源免费的跨平台计算机视觉库,它向C#和VB.NET开发者提供了OpenCV库的大部分功能。 教程VB.net版本请访问…

ctfshow--信息收集题目全解

前言 欢迎来到我的博客 个人主页:北岭敲键盘的荒漠猫-CSDN博客 本文记录ctfshow信息收集部分打靶记录 web1 这题弱智&#xff0c;f12进入查看源码&#xff0c;flag在注释里。 (这告诉我们&#xff0c;开发者的注释我们也是可以看到的&#xff0c;所以版权&#xff0c;源码地址&…

个人随想:嵌入学习桌的智能学习与陪伴助手

随着大模型技术的快速发展&#xff0c;我们对于7B、70B、80B甚至405B等开源大模型已经不陌生。在有GPU支持的情况下&#xff0c;许多人会倾向选择更大参数的模型&#xff0c;因为通常参数越大&#xff0c;效果越好&#xff0c;这已成为行业共识。 . 然而&#xff0c;随着量化技…

.NET 一款在线解密Web.config的脚本

01阅读须知 此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等&#xff08;包括但不限于&#xff09;进行检测或维护参考&#xff0c;未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此文所提供的信息而造成的直接或间接后果和损失&#xf…

man命令详解

一、man命令简介&#xff1a; man是manual的缩写。操作手册之意。 本地的帮助文档称为man pages&#xff0c;这些操作手册随着软件安装而安装到本地&#xff0c;可以使用man命令进行查询。 随着软件包的安装有些操作手册会以文档的方式放在/usr/share/doc目录当中。…

网络设备安全

网络设备安全概况 交换机安全威胁&#xff1a;交换机是网络基础设备&#xff0c;负责网络通信数据包的交换传输 交换机面临的网络安全威胁&#xff1a; 路由器安全威胁 网络设备安全机制与实现技术 认证机制&#xff1a;为防止网络设备滥用&#xff0c;网络设备读用户身份进行…

c# socket通信实例

服务器端 主要代码 //服务器socket private Socket serverSocket; private void InitServerSocket() {//创建终结点&#xff08;EndPoint&#xff09;IPAddress ip IPAddress.Any;IPEndPoint ipe new IPEndPoint(ip, 10030);//创建 socket 并开始监听serverSocket new Soc…

PyQT开发总结

用PyQT开发了一个界面小程序&#xff0c;记录一下。 pyuic和pyrcc pyuic &#xff08;PYthon User Interface Compiler&#xff09;是一个命令行工具&#xff0c;用于将 Qt Designer 生成的 .ui 文件转换成 Python 代码。pyrcc 用于处理 Qt 资源文件&#xff08;如图片&#…

海外云手机有哪些推荐?

随着云手机的发展&#xff0c;越来越多的企业和个人开始使用云手机来满足他们的海外业务需求。用户可以通过云手机实现方便、快捷的海外访问&#xff0c;一般用来进行tiktok运营、亚马逊电商运营、海外社媒运营等操作。海外云手机平台有很多&#xff0c;以下是一些比较好的云手…