17-C++ 数据结构 - 栈

news2024/11/16 19:39:37

📖 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.coloradmin.cn/o/810354.html

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

相关文章

68. 文本左右对齐

题目链接&#xff1a;力扣 解题思路&#xff1a;遍历单词数组&#xff0c;确定每一行的单词数量&#xff0c; 之后就可以得到每一个需要补充的空格数量。从而得到单词之间需要补充的空格数量。具体算法如下&#xff1a; 确定每一行的单词数量 初始值&#xff1a; num 0&…

基于springboot+mybatis+jsp日用品商城管理系统

基于springbootmybatisjsp日用品商城管理系统 一、系统介绍二、功能展示1.主页(客户)2.登陆、注册&#xff08;客户&#xff09;3.我的购物车(客户)4.我的订单&#xff08;客户&#xff09;5.我的商铺&#xff08;商家&#xff09;6.商品管理&#xff08;商家&#xff09;7.订单…

【编程规范】一文讲解开发中的命名规范

命名规范 好的代码本身就是注释, 所以我们需要统一命名风格。 ​ 在本文中&#xff0c;将从大到小&#xff0c;从外到内&#xff0c;总结Java编程中的命名规范。文中将会涉及到日常工作中常见的命名示例&#xff0c;如包命名&#xff0c;类命名&#xff0c;接口命名&#xff0c…

计算机网络——学习笔记

付费版&#xff1a;直接在上面的CSDN资源下载 免费版&#xff1a;https://wwsk.lanzouk.com/ijkcj13tqmyb 示例图&#xff1a;

BIOS相关知识

简介 BIOS&#xff08;Basic Input Output System&#xff09;基本输入输出系统&#xff0c;固化在服务器主板的专用ROM中&#xff0c;是加载在服务器硬件系统上最基本的运行程序。BIOS位于硬件和系统中间&#xff0c;用来初始化硬件&#xff0c;为操作系统运行做准备 功能 …

C语言进阶——文件的打开(为什么使用文件、什么是文件、文件的打开和关闭)

目录 为什么使用文件 什么是文件 程序文件 数据文件 文件名 文件的打开和关闭 文件指针 打开和关闭 为什么使用文件 在之前学习通讯录时&#xff0c;我们可以给通讯录中增加、删除数据&#xff0c;此时数据是存放在内存中&#xff0c;当程序退出的时候&#xff0c;通讯…

【算法提高:动态规划】1.1 数字三角形模型

文章目录 例题列表1015. 摘花生1018. 最低通行费1027. 方格取数&#xff08;两条路径同时走&#xff09;⭐⭐⭐⭐⭐275. 传纸条&#xff08;转换成 两条路径同时走&#xff09; 例题列表 1015. 摘花生 https://www.acwing.com/problem/content/1017/ 状态要么从左转移过来&…

基于双层优化的大型电动汽车时空调度(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

❤️创意网页:贪吃蛇游戏 - 创造一个经典的小游戏

✨博主&#xff1a;命运之光 &#x1f338;专栏&#xff1a;Python星辰秘典 &#x1f433;专栏&#xff1a;web开发&#xff08;简单好用又好看&#xff09; ❤️专栏&#xff1a;Java经典程序设计 ☀️博主的其他文章&#xff1a;点击进入博主的主页 前言&#xff1a;欢迎踏入…

c++的函数定义中,只提供形参类型,不提供形参名

如上图所示&#xff0c;显示了 c 语法里的一种不常见的应用。若没有对某个形参的后续使用的要求&#xff0c;可以不提供形参名的&#xff0c;也能编译通过。这么写法的作用&#xff0c;可以以第一个参数的类型不同&#xff0c;来实现函数的重载。在阅读源码&#xff0c;在vs201…

【Linux】UDP协议

​&#x1f320; 作者&#xff1a;阿亮joy. &#x1f386;专栏&#xff1a;《学会Linux》 &#x1f387; 座右铭&#xff1a;每个优秀的人都有一段沉默的时光&#xff0c;那段时光是付出了很多努力却得不到结果的日子&#xff0c;我们把它叫做扎根 目录 &#x1f449;传输层&a…

目标检测应用场景—数据集【NO.14】行人跌倒测试

写在前面&#xff1a;数据集对应应用场景&#xff0c;不同的应用场景有不同的检测难点以及对应改进方法&#xff0c;本系列整理汇总领域内的数据集&#xff0c;方便大家下载数据集&#xff0c;若无法下载可关注后私信领取。关注免费领取整理好的数据集资料&#xff01;今天分享…

什么是线程?线程和进程的关系?如何创建/查看线程?

文章目录 一. 认识线程(Thread)1.1 概念1.1.1 什么是线程1.1.2 线程存在的意义1.1.3 进程和线程之间的区别和联系1.1.4 Java的线程和操作系统的线程 1.2 创建线程① 继承Thread类② 实现Runnable 接口对比两种方法③ 变形写法④ 其他写法 1.3 查看线程 一. 认识线程(Thread) 1…

C++之科学技术法e使用(一百七十二)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

阿里云服务器全方位介绍_性能功能优势和租用费用

阿里云服务器全方位介绍包括云服务器ECS优势、云服务器租用价格、云服务器使用场景及限制说明&#xff0c;阿里云服务器网分享云服务器ECS介绍、个人和企业免费试用、云服务器活动、云服务器ECS规格、优势、功能及应用场景详细说明&#xff1a; 目录 什么是云服务器ECS&#…

学习笔记22 set

一、概述 Set是一种集合类型&#xff0c;可以快速在大量数据中查找特定值。 Set存储无序序列中的元素&#xff0c;并且不允许重复。与列表不同&#xff0c;列表中的数据可以通过索引访问&#xff0c;但是在集合中&#xff0c;元素没有与集合中的位置相关联。 Set是优化了搜索…

消息队列总结(4)- RabbitMQ Kafka RocketMQ高性能方案

1.RabbitMQ的高性能解决方案 1.1 发布确认机制 RabbitMQ提供了3种生产者发布确认的模式&#xff1a; 简单模式&#xff08;Simple Mode&#xff09;&#xff1a;生产者发送消息后&#xff0c;等待服务器确认消息已经被接收。这种模式下&#xff0c;生产者发送消息后会阻塞&am…

M5ATOMS3基础03给ROS1发一个问候(rosserial)

引出问题 关于之前2020年的博客&#xff1a; 01. ESP8266和ROS调试一些问题汇总 02. ESP8266和ESP32配置&#xff08;需使用ROS1和ROS2&#xff09; 效果展示 使用M5ATOMS3与ROS1&#xff08;kinetic&#xff0c;melodic&#xff0c;noetic&#xff09;版本通信比较通用的是…

BUU [网鼎杯 2020 朱雀组]phpweb

BUU [网鼎杯 2020 朱雀组]phpweb 众生皆懒狗。打开题目&#xff0c;只有一个报错&#xff0c;不知何从下手。 翻译一下报错&#xff0c;data()函数:,还是没有头绪&#xff0c;中国有句古话说的好“遇事不决抓个包” 抓个包果然有东西&#xff0c;仔细一看这不就分别是函数和参…

【算法基础:贪心】6. 贪心

文章目录 区间问题905. 区间选点&#xff08;排序 贪心&#xff09;908. 最大不相交区间数量&#xff08;排序 贪心&#xff09;906. 区间分组&#xff08;排序 优先队列 贪心&#xff09;⭐907. 区间覆盖&#xff08;排序 贪心&#xff09; Huffman树148. 合并果子&#…