17-C++ 数据结构 - 栈

news/2024/4/29 12:02:08/文章来源:https://blog.csdn.net/mingfeng4923/article/details/132001779

📖 1.1 什么是栈

栈是一种线性数据结构,具有后进先出(Last-In-First-Out,LIFO)的特点。可以类比为装满盘子的餐桌,每次放盘子都放在最上面,取盘子时也从最上面取,因此最后放进去的盘子最先取出。栈的典型应用场景有函数调用、括号匹配、表达式求值等。

元素从固定一侧开口进入和离开栈的操作,分别称为入栈和出栈。

栈中元素由深到浅存储,我们将栈最深的存储位置称为栈底,当前栈中最外围元素所在的位置则称为栈顶。

在这里插入图片描述

栈底通常固定不变,而栈顶则由当前栈中最外侧元素位置(栈中元素数量)确定。

由栈的特点可知栈的插入和删除(入栈和出栈)操作都是在栈顶这一端进行的。

栈顶(Top):线性表允许进行插入删除的那一端。
栈底(Bottom):固定的,不允许进行插入和删除的另一端。
空栈:不含任何元素的空表。

栈又称为后进先出(Last In First Out)的线性表,简称LIFO结构

栈的常见基本操作
InitStack(&S):初始化一个空栈S 。
StackEmpty(S):判断一个栈是否为空,若栈为空则返回true,否则返回false。
Push(&S, x):进栈(栈的插入操作),若栈S未满,则将x加入使之成为新栈顶。
Pop(&S, &x):出栈(栈的删除操作),若栈S非空,则弹出栈顶元素,并用x返回。
GetTop(S, &x):读栈顶元素,若栈S非空,则用x返回栈顶元素。
DestroyStack(&S):栈销毁,并释放S占用的存储空间(“&”表示引用调用)。

💻 1.2 栈的实现(数组模拟)

栈的实现可以使用数组来模拟。我们可以定义一个固定大小的数组和一个指向栈顶的指针。栈顶指针初始化为 -1,表示栈为空。每次入栈操作时,将元素放入数组并将栈顶指针加一;出栈操作时,将栈顶指针减一。

#include <iostream>
using namespace std;const int MAX_SIZE = 100; // 栈的最大容量
int stack[MAX_SIZE]; // 栈的数组
int top = -1; // 栈顶指针// 入栈操作
void push(int x) {if (top >= MAX_SIZE - 1) {cout << "栈已满,无法入栈!" << endl;return;}stack[++top] = x;
}// 出栈操作
void pop() {if (top == -1) {cout << "栈为空,无法出栈!" << endl;return;}top--;
}// 获取栈顶元素
int peek() {if (top == -1) {cout << "栈为空,无栈顶元素!" << endl;return -1;}return stack[top];
}// 判断栈是否为空
bool isEmpty() {return top == -1;
}// 获取栈的大小
int size() {return top + 1;
}int main() {push(1);push(2);push(3);cout << "当前栈顶元素:" << peek() << endl;cout << "栈的大小:" << size() << endl;pop();cout << "当前栈顶元素:" << peek() << endl;cout << "栈是否为空:" << (isEmpty() ? "是" : "否") << endl;return 0;
}

运行结果:

当前栈顶元素:3
栈的大小:3
当前栈顶元素:2
栈是否为空:否

📚 1.3 栈的实现(STL 方法)

在 C++ 中,我们也可以使用标准模板库(STL)提供的 stack 容器来实现栈。使用 stack 容器非常方便,不需要手动处理数组和指针。

#include <iostream>
#include <stack>
using namespace std;int main() {stack<int> st;st.push(1);st.push(2);st.push(3);cout << "当前栈顶元素:" << st.top() << endl;cout << "栈的大小:" << st.size() << endl;st.pop();cout << "当前栈顶元素:" << st.top() << endl;cout << "栈是否为空:" << (st.empty() ? "是" : "否") << endl;return 0;
}

运行结果:

当前栈顶元素:3
栈的大小:3
当前栈顶元素:2
栈是否为空:否

使用 stack 容器,我们可以更方便地实现栈的入栈、出栈、获取栈顶元素等操作,而无需自己处理底层的数据结构。

🚂 1.4 出入栈顺序(火车调度案例)

火车调度是一个经典的栈的应用场景。给定 n 辆火车的进站顺序,请输出所有可能的出站顺序。

我们使用递归来生成所有可能的出站顺序。对于每一辆火车,它可以先进站再出站,也可以直接从进站过程中出站。我们不断尝试所有可能的出站顺序,直到所有火车都出站。

#include <iostream>
#include <vector>
using namespace std;void dfs(vector<int>& in, vector<int>& out, vector<int>& path) {if (in.empty() && out.empty()) {for (int num : path) {cout << num << " ";}cout << endl;return;}if (!in.empty()) {int num = in.back();in.pop_back();path.push_back(num);dfs(in, out, path);path.pop_back();in.push_back(num);}if (!out.empty()) {int num = out.back();out.pop_back();path.push_back(num);dfs(in, out, path);path.pop_back();out.push_back(num);}
}int main() {vector<int> in = {1, 2, 3};vector<int> out;vector<int> path;dfs(in, out, path);return 0;
}

运行结果:

1 2 3 
1 3 2 
2 1 3 
2 3 1 
3 1 2 
3 2 1 

🧩 1.5 栈的应用

有效的括号

题目描述

给定一个只包括 '('')''{''}''['']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。
  3. 每个右括号都有一个对应的相同类型的左括号。

示例 1:

输入:s = "()"
输出:true

示例 2:

输入:s = "()[]{}"
输出:true

示例 3:

输入:s = "(]"
输出:false

提示:

  • 1 <= s.length <= 104
  • s 仅由括号 '()[]{}' 组成

力扣官方题解https://leetcode.cn/problems/valid-parentheses/solutions/373578/you-xiao-de-gua-hao-by-leetcode-solution/

我们遍历给定的字符串 s。当我们遇到一个左括号时,我们会期望在后续的遍历中,有一个相同类型的右括号将其闭合。由于后遇到的左括号要先闭合,因此我们可以将这个左括号放入栈顶。
当我们遇到一个右括号时,我们需要将一个相同类型的左括号闭合。此时,我们可以取出栈顶的左括号并判断它们是否是相同类型的括号。如果不是相同的类型,或者栈中并没有左括号,那么字符串 s 无效,返回False。为了快速判断括号的类型,我们可以使用哈希表存储每一种括号。哈希表的键为右括号,值为相同类型的左括号。
在遍历结束后,如果栈中没有左括号,说明我们将字符串 s 中的所有左括号闭合,返回 True,否则返回 False。
注意到有效字符串的长度一定为偶数,因此如果字符串的长度为奇数,我们可以直接返回 False,省去后续的遍历判断过程。

栈在括号匹配中有着重要的应用。给定一个只包含 ()[]{} 的字符串,判断括号是否匹配。

使用栈可以轻松解决这个问题。遍历字符串中的每个字符,如果是左括号,将其入栈;如果是右括号,判断与栈顶元素是否匹配,若匹配则出

栈,否则返回 false。最后检查栈是否为空,为空则括号匹配。

#include <iostream>
#include <stack>
#include <unordered_map>
using namespace std;bool isValid(string s) {stack<char> st;unordered_map<char, char> mapping = {{')', '('}, {']', '['}, {'}', '{'}};for (char c : s) {if (c == '(' || c == '[' || c == '{') {st.push(c);} else if (c == ')' || c == ']' || c == '}') {if (st.empty() || st.top() != mapping[c]) {return false;}st.pop();}}return st.empty();
}int main() {cout << isValid("()") << endl;         // 输出:1 (true)cout << isValid("()[]{}") << endl;     // 输出:1 (true)cout << isValid("(]") << endl;         // 输出:0 (false)return 0;
}

在这里插入图片描述

在这里插入图片描述

📝 总结

栈是一种非常重要的数据结构,在计算机算法中有着广泛的应用。通过模拟入栈和出栈操作,我们可以解决很多实际问题,比如火车调度、括号匹配等。同时,C++ 中也提供了标准模板库(STL)中的 stack 容器,方便我们使用栈来解决问题。熟练掌握栈的使用将会对你的编程技能有很大的提升。

⭐️希望本篇文章对你有所帮助。

⭐️如果你有任何问题或疑惑,请随时向提问。

⭐️感谢阅读!

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

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

相关文章

maven引入本地jar包的简单方式【IDEA】【SpringBoot】

前言 想必点进来看这篇文章的各位&#xff0c;都是已经习惯了Maven从中央仓库或者阿里仓库直接拉取jar包进行使用。我也是&#x1f921;&#x1f921;。 前两天遇到一个工作场景&#xff0c;对接三方平台&#xff0c;结果对方就是提供的一个jar包下载链接&#xff0c;可给我整…

RustDesk 1.2 现已发布

RustDesk 1.2 现已发布&#xff0c;此版本采用 Flutter 重写桌面版本&#xff0c;支持 Wayland 被控。 一些值得关注的变化有&#xff1a; 用 Flutter 重写支持 ipv6&#xff08;Beta&#xff09;增加一次性密码QuickSupport &#xff08;Beta&#xff09;硬件编解码器 H264 /…

51单片机——串行口通信

目录 1、51单片机串口通信介绍 2、串行口相关寄存器 2.1 、串行口控制寄存器SCON和PCON 2.1.1 SCON&#xff1a;串行控制寄存器 (可位寻址) 2.1.2 PCON&#xff1a;电源控制寄存器&#xff08;不可位寻址&#xff09; 2.2、串行口数据缓冲寄存器SBUF 2.3、从机地址控制…

关于element ui 安装失败的问题解决方法、查看是否安装成功及如何引入

Vue2引入 执行npm i element-ui -S报错 原因&#xff1a;npm版本太高 报错信息&#xff1a; 解决办法&#xff1a; 使用命令&#xff1a; npm install --legacy-peer-deps element-ui --save 引入&#xff1a; 在main.js文件中引入 //引入Vue import Vue from vue; //引入…

ubuntu23.04 flush DNS caches

如何在Ubuntu 23.04中刷新DNS缓存 现在&#xff0c;如果你运行的是Ubuntu 23.04&#xff0c;"系统解决 "的方法将不再适用于你。让我们检查一下你目前的缓存大小。打开你的Ubuntu终端&#xff0c;运行以下command&#xff1a; resolvectl statistics现在&#xff0c…

Android Unit Test

一、测试基础知识 1.1 测试级别 测试金字塔&#xff08;如图 2 所示&#xff09;说明了应用应如何包含三类测试&#xff08;即小型、中型和大型测试&#xff09;&#xff1a; 小型测试是指单元测试&#xff0c;用于验证应用的行为&#xff0c;一次验证一个类。 中型测试是指…

Spring Cloud Alibaba - Nacos源码分析(三)

目录 一、Nacos客户端服务订阅的事件机制 1、监听事件的注册 2、ServiceInfo处理 serviceInfoHolder.processServiceInfo 一、Nacos客户端服务订阅的事件机制 Nacos客户端订阅的核心流程&#xff1a;Nacos客户端通过一个定时任务&#xff0c;每6秒从注册中心获取实例列表&…

内网隧道代理技术(十四)之 Earthworm的使用(一级代理)

Earthworm的使用(一级代理) ew 全称是EarchWorm,是一套轻量便携且功能强大的网络穿透工具,基于标准C开发,具有socks5代理、端口转发和端口映射三大功能,可在复杂网络环境下完成网络穿透,且支持全平台(Windows/Linux/Mac)。该工具能够以“正向”、“反向”、“多级级联”…

51单片机双机通信

对于这个51单片机双机通信&#xff0c;之前无聊做的玩的&#xff0c;但是既然写了一篇51单片机串行口通信的博客&#xff0c;那就顺便出来供大家学习&#xff0c;希望能够帮助到一些刚刚接触51单片机的朋友。废话不多讲&#xff0c;直接上正题。 1、实习任务 1.1 任务目的 通…

oCPC实践录 | oCPC下机制设计变得毫无意义?(2)无声的战争

接上回oCPC实践录 | oCPC下机制设计变得毫无意义&#xff1f;&#xff08;1&#xff09;事出异常必有妖&#xff0c;互联网广告最开始采用的广义第一价格密封拍卖&#xff08;GFP)&#xff0c;对广告主而言&#xff0c;需要不断感知竞争对手的变化&#xff0c;修改报价&#xf…

Power BI-网关设置与云端报表定时刷新(一)

网关的工作原理 网关是将本地数据传输至云端的桥梁&#xff0c;不仅Power BI能使用&#xff0c;其他微软软件也能够使用。 我们发布在云上的报表&#xff0c;发布后是静态的&#xff0c;不会自动刷新。需要通过网关设置定时刷新。 安装与设置 1.登录到Powerbi 在线服务–设置…

组合模式——树形结构的处理

1、简介 1.1、概述 树形结构在软件中随处可见&#xff0c;例如操作系统中的目录结构、应用软件中的菜单、办公系统中的公司组织结构等。如何运用面向对象的方式来处理这种树形结构是组合模式需要解决的问题。组合模式通过一种巧妙的设计方案使得用户可以一致性地处理整个树形…

Windows下Nginx安装与配置教程

一、前言 1、Nginx是什么&#xff1f; Nginx是一个开源的Web服务器&#xff0c;同时Nginx也提供了反向代理和负载均衡的功能。 Nginx通常作为负载均衡器暴露在外网接受用户请求&#xff0c;同时也使用其反向代理的功能&#xff0c;将用户的请求转发到实际提供服务的内网服务器…

Windows 11 下 OpenFace 2.2.0 的安装

写在前面 最近需要做关于面部的东西&#xff0c;所以需要使用到OpenFace这个工具&#xff0c;本文仅用来记录本人安装过程以供后续复现&#xff0c;如果可以帮助到读者也是非常荣幸。 安装过程 不编译直接使用 这种方法可以直接从官方下载下来编译好的exe以及gui进行使用&a…

移动端适配rem

1.安装amfe-flexible和postcss-pxtorem&#xff0c; npm install amfe-flexible --save npm install postcss-pxtorem5.1.1 (这里我使用的postcss-pxtorem是5.1.1版本)或者在pageage.json中写入 "amfe-flexible": "^2.2.1","postcss-pxtorem": …

一个 SpringBoot 项目能处理多少请求

首先&#xff0c;这个问题有坑&#xff0c;因为 spring boot 不处理请求&#xff0c;只是把现有的开源组件打包后进行了版本适配、预定义了一些开源组件的配置通过代码的方式进行自动装配进行简化开发。这是 spring boot 的价值。 如果我是面试官&#xff0c;我不会问这种问题。…

带wiringPi库的交叉编译 ---宿主机x86Ubuntu,目标机ARMv8 aarch64(香橙派)

带wiringPi库的交叉编译如何进行 先交叉编译wiringPi库&#xff0c;编译出的库适合香橙派&#xff0c;这时候交叉编译可执行程序的平台和链接库的格式也是正确的&#xff0c;然后通过-I和-L来指定链接的wiringPi库的头文件和库的位置&#xff0c;但是现在还没有学习过&#xf…

如何有效地使用ChatGPT写小说讲故事?

​构思故事情节&#xff0c;虽有趣但耗时&#xff0c;容易陷入写作瓶颈。ChatGPT可提供灵感&#xff0c;帮你解决写作难题。要写出引人入胜的故事&#xff0c;关键在于抓住八个要素——主题、人物、视角、背景、情节、语气、冲突和解决办法。 直接给出故事模板&#xff0c;你可…

算法39:Excel 表列序号

一、需求 给你一个字符串 columnTitle &#xff0c;表示 Excel 表格中的列名称。返回 该列名称对应的列序号 。 例如&#xff1a; A -> 1 B -> 2 C -> 3 … Z -> 26 AA -> 27 AB -> 28 … 示例 1&#xff1a; 输入: columnTitle “A” 输出: 1 示例 2&…