“探秘数据结构:栈的奇妙魔力“

每日一言

兰有秀兮菊有芳,怀佳人兮不能忘。 —刘彻-


栈的概念及结构

栈(Stack) :一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。类似于一个垂直摞起来的盘子,想要拿或放只能从顶上,而不能从底部操作。
在这里插入图片描述

栈的一些操作

压栈(push):栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈(pop):栈的删除操作叫做出栈。出数据也在栈顶
获取栈顶元素(top):获取栈顶元素,但不将其从栈中移除。
判断栈是否为空(isEmpty):判断栈是否为空操作会返回一个布尔值,表示栈是否为空。

在这里插入图片描述

栈的实现

顺序栈

顺序栈是一种基于数组实现的栈数据结构。
在这里插入图片描述

代码实现

//准备工作

	int[] array;int size;//当前栈内的空间大小//创建栈,为栈分配存储空间public MyStack() {array = new int[3];}

//入栈

public void push(int val) {//检查是否需要扩容ensureCapacity();//入栈,并将栈的大小自增1array[size++] = val;}

//出栈

public int pop() {//因为top()方法中已经检查了栈是否为空,所以这里就不再检查了int val = top();size--;return val;}

//判断栈是否为空

public boolean isEmpty() {return size == 0;}

//获取栈顶元素

public int top() {if (isEmpty()) {System.out.println("栈为空!");return -1;//这里也可以写成抛出一个异常}return array[size - 1];}

//检查扩容

public void ensureCapacity() {//检查栈是否已满if (size == array.length) {//已满,将栈的容量扩大一倍array = Arrays.copyOf(array, size * 2);}}

链栈

采用链式存储结构实现的栈称为链栈,链栈通常采用单链表来实现,因此其结构与单链表的结构相同由于栈的插入和删除操作仅限制在栈顶位置进行,所以采用单链表的表头指针作为栈顶指针。

代码实现
//准备工作

	private Element base;//栈底指针private Element top;//栈顶指针//栈中的每个节点private class Element {private int data;private Element next;}

//入栈

public void push(int val) {Element newElem = new Element();newElem.data = val;newElem.next = top;top = newElem;}

//出栈

 public int pop() {if(isEmpty()) {System.out.println("栈为空!");return -1;//这里也可以抛出异常}int val = top.data;top = top.next;return val;}

//判断栈是否为空

public boolean isEmpty() {//栈底指针和栈顶指针指向同一位置,此时栈为空return base == top;}

//获取栈顶元素

public int top() {return top.data;}

栈小结

⭐栈的特点是?
先进后出

⭐顺序栈与链栈哪个更好?

顺序栈和链栈各有优缺点,没有绝对的“更好”。选择哪种实现方式取决于问题的要求和特点。

⭐顺序栈(数组实现)的优点是:

  1. 存储空间连续,可以利用数组的随机访问特性,对栈的操作具有较高的效率。
  2. 实现简单,代码量较少。

⭐顺序栈(数组实现)的缺点是:

  1. 存储空间固定,创建栈时必须指定大小,大小无法动态调整。
  2. 当栈满时需要进行扩容,需要重新分配更大的内存空间,并将原有数据复制到新的内存空间中。

⭐链栈的优点是:

  1. 存储空间可以动态分配,不受固定大小的限制。
  2. 插入和删除元素的操作只需要修改指针,不需要移动大量的数据,相对较快。

⭐链栈的缺点是:

  1. 需要额外的指针指向下一个节点,增加了存储空间的开销。
  2. 由于每个节点需要存储指针,导致链栈的存储密度较低,对内存的利用率较低。

有关栈的一些题

1. 有效的括号

题目链接: 有效的括号

题目

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

有效字符串需满足:

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

  • 示例 1:
    输入:s = “()”
    输出:true

  • 示例 2:
    输入:s = “()[]{}”
    输出:true

  • 示例 3:
    输入:s = “(]”
    输出:false

提示:
1 <= s.length <= 104
s 仅由括号 ‘()[]{}’ 组成


思路

  1. 遍历字符串中的每个字符。
  2. 如果字符是一个开括号(即’(', ‘[’, ‘{’),它会被压入栈中。
  3. 如果字符是一个闭括号,则检查栈是否为空。如果栈为空,意味着没有相应的开括号,字符串无效。如果栈不为空,则检查栈的顶部是否包含相应的开括号。如果是,栈的顶部元素将被弹出。如果不是,意味着字符串无效。
  4. 在遍历字符串的所有字符之后,检查栈是否为空。如果栈为空,意味着所有的开括号已经匹配并从栈中弹出,字符串有效。如果栈不为空,意味着还有剩余的开括号,字符串无效。

代码

class Solution {public boolean isValid(String s) {Stack<Character> stack = new Stack<>();for(int i = 0; i < s.length(); i++) {char ch = s.charAt(i);if(ch == '(' || ch == '[' || ch == '{') {stack.add(ch);}else {if(stack.isEmpty()){return false;}else { if (ch == ')' && stack.peek() == '(' ||ch == ']' && stack.peek() == '[' ||ch == '}' && stack.peek() == '{' ) {stack.pop();} else {return false;}}}}return stack.isEmpty();}
}

2. 逆波兰表达式求值

题目链接: 逆波兰表达式求值

题目

给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。

请你计算该表达式。返回一个表示表达式值的整数。

注意:
有效的算符为 ‘+’、‘-’、‘*’ 和 ‘/’ 。
每个操作数(运算对象)都可以是一个整数或者另一个表达式。
两个整数之间的除法总是 向零截断 。
表达式中不含除零运算。
输入是一个根据逆波兰表示法表示的算术表达式。
答案及所有中间计算结果可以用 32 位 整数表示。

  • 示例 1:
    输入:tokens = [“2”,“1”,“+”,“3”,“*”]
    输出:9
    解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9

  • 示例 2:
    输入:tokens = [“4”,“13”,“5”,“/”,“+”]
    输出:6
    解释:该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6

  • 示例 3:
    输入:tokens = [“10”,“6”,“9”,“3”,“+”,“-11”,““,”/“,””,“17”,“+”,“5”,“+”]
    输出:22
    解释:该算式转化为常见的中缀算术表达式为:
    ((10 * (6 / ((9 + 3) * -11))) + 17) + 5
    = ((10 * (6 / (12 * -11))) + 17) + 5
    = ((10 * (6 / -132)) + 17) + 5
    = ((10 * 0) + 17) + 5
    = (0 + 17) + 5
    = 17 + 5
    = 22

提示:
1 <= tokens.length <= 104
tokens[i] 是一个算符(“+”、“-”、“*” 或 “/”),或是在范围 [-200, 200] 内的一个整数

思路

用循环遍历整个字符串数组,如果当前字符为数字,则入栈;如果当前字符为运算符,则将栈中的两个数字弹出,根据运算符参与相应的运算。最后栈当中会剩余一个最终结果,return返回这个结果。

代码

class Solution {public boolean isOperation(String tmp) {return tmp.equals("+") || tmp.equals("-") ||tmp.equals("*") ||tmp.equals("/");}public int evalRPN(String[] tokens) {Stack<Integer> stack = new Stack<>();for(int i = 0; i < tokens.length; i++) {String tmp = tokens[i];if(!isOperation(tmp)) {stack.add(Integer.valueOf(tmp));} else {int num2 = stack.pop();int num1 = stack.pop();switch (tmp) {case "+":stack.push(num1 + num2);break;case "-":stack.push(num1 - num2);break;case "*":stack.push(num1 * num2);break;case "/":stack.push(num1 / num2);break;}}}return stack.pop();}
}

3. 栈的压入、弹出序列

题目链接:栈的压入、弹出序列

题目

描述
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列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. 定义一个整型变量j用于指示出栈数组popV的位置,初始化为0;定义一个Stack对象stack来模拟入栈过程。
  2. 使用循环遍历入栈数组pushV,
  3. 如果当前入栈元素不等于出栈数组popV中指针j所指向的元素,则将当前入栈元素压入栈stack中。
  4. 如果当前入栈元素等于出栈数组popV中指针j所指向的元素,则进行出栈操作:
  5. 将指针j向后移动一位,表示出栈数组中的下一个元素。
  6. 检查栈顶元素是否与popV[j]相等,如果相等,则继续出栈,直到栈为空或者栈顶元素与popV[j]不相等。
  7. 判断最终栈是否为空:遍历结束后,如果栈为空,则说明入栈和出栈顺序是匹配的,返回true;否则返回false。

代码

import java.util.*;public class Solution {public boolean IsPopOrder(int[] pushV, int[] popV) {int j = 0;Stack<Integer> stack = new Stack<>();for(int i = 0; i < pushV.length; i++) {if(pushV[i] != popV[j]) {stack.push(pushV[i]);} else {j++;while(!stack.isEmpty() && j < popV.length && popV[j] == stack.peek()) {j++;stack.pop();}}}return stack.isEmpty();}
}

结语

栈的特点:先进后出

有两种实现栈的方法,我该用哪个?

如果存储空间的大小事先已知且固定,并且对栈的操作效率要求较高,可以选择顺序栈。如果存储空间的大小不确定,或者频繁地进行插入和删除操作,并且对栈的大小没有严格的限制,可以选择链栈。


都看到这里啦!真棒(*^▽^*)

可以给作者一个免费的赞赞吗,这将会鼓励我继续创作,谢谢大家

编程小白写作,如有纰漏或错误,欢迎指正


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

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

相关文章

Python深度学习034:cuda的环境如何配置

文章目录 1.安装nvidia cuda驱动CMD中看一下cuda版本:下载并安装cuda驱动2.创建虚拟环境并安装pytorch的torch_cuda3.测试附录1.安装nvidia cuda驱动 CMD中看一下cuda版本: 注意: 红框的cuda版本,是你的显卡能装的最高的cuda版本,所以可以选择低于它的版本。比如我的是11…

AI图像重绘解决方案

高质量的图像素材往往成本高昂且制作周期长&#xff0c;给企业带来了不小的困扰。美摄科技凭借其领先的AI图像重绘解决方案&#xff0c;为企业提供了一种高效、便捷且成本可控的图像优化途径&#xff0c;助力企业重塑视觉形象&#xff0c;引领市场新风尚。 美摄科技的AI图像重…

探索设计模式的魅力:AI大模型如何赋能C/S模式,开创服务新纪元

​&#x1f308; 个人主页&#xff1a;danci_ &#x1f525; 系列专栏&#xff1a;《设计模式》 &#x1f4aa;&#x1f3fb; 制定明确可量化的目标&#xff0c;坚持默默的做事。 AI大模型如何赋能C/S模式&#xff0c;开创服务新纪元 数字化飞速发展的时代&#xff0c;AI大模型…

【浅尝C++】STL第三弹=>list常用接口使用示例/list底层结构探索/list模拟实现代码详解

&#x1f3e0;专栏介绍&#xff1a;浅尝C专栏是用于记录C语法基础、STL及内存剖析等。 &#x1f3af;每日格言&#xff1a;每日努力一点点&#xff0c;技术变化看得见。 文章目录 list介绍list常用接口使用示例构造类函数迭代器属性与元素获取增删改操作 list底层结构探索list模…

数据结构——第5章 树和二叉树

1 二叉树 二叉树和树都属于树形结构&#xff0c;但两者互不包含。即二叉树不是特殊的树。 1.1 二叉树的基本概念 1.2 二叉树的顺序存储 仅适用于完全二叉树 #define MaxSize 100 typedef int ElemType; typedef struct TreeNode{ElemType value;//结点中的数据元素bool isE…

手机有线投屏到直播姬pc端教程

1 打开哔哩哔哩直播姬客户端并登录(按下图进行操作) 2 手机用usb数据线连接电脑(若跳出安装驱动的弹窗点击确定或允许),usb的连接方式为仅充电(手机差异要求为仅充电),不同品牌手机要求可能不一样,根据实际的来 3 在投屏过程中不要更改usb的连接方式(不然电脑会死机需要重启) …

微服务(基础篇-007-RabbitMQ部署指南)

目录 05-RabbitMQ快速入门--介绍和安装_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1LQ4y127n4?p65&vd_source60a35a11f813c6dff0b76089e5e138cc 1.单机部署 1.1.下载镜像 1.2.安装MQ 2.集群部署 2.1.集群分类 2.2.设置网络 视频地址&#xff1a; 05-Rab…

LeetCode刷题记(一):1~30题

1. 两数之和 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元素在答案里不能重复出现。 你可以…

蓝桥杯第793题——排水系统

题目描述 对于一个城市来说&#xff0c;排水系统是极其重要的一个部分。 有一天&#xff0c;小 C 拿到了某座城市排水系统的设计图。排水系统由 n 个排水结点&#xff08;它们从 1∼n 编号&#xff09;和若干个单向排水管道构成。每一个排水结点有若干个管道用于汇集其他排水…

读取信息boot.bin和xclbin命令

bootgen读Boot.bin命令 johnjohn-virtual-machine:~/project_zynq/kv260_image_ubuntu22.04$ bootgen -read BOOT-k26-starter-kit-202305_2022.2.bin xclbinutil读xclbin命令 johnjohn-virtual-machine:~/project_zynq/kv260_image_ubuntu22.04$ xclbinutil -i kv260-smartca…

整型之韵,数之舞:大小端与浮点数的内存之旅

✨✨欢迎&#x1f44d;&#x1f44d;点赞☕️☕️收藏✍✍评论 个人主页&#xff1a;秋邱’博客 所属栏目&#xff1a;人工智能 &#xff08;感谢您的光临&#xff0c;您的光临蓬荜生辉&#xff09; 1.0 整形提升 我们先来看看代码。 int main() {char a 3;char b 127;char …

篮球竞赛预约平台的设计与实现|Springboot+ Mysql+Java+ B/S结构(可运行源码+数据库+设计文档)

本项目包含可运行源码数据库LW&#xff0c;文末可获取本项目的所有资料。 推荐阅读300套最新项目持续更新中..... 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 2024年56套包含ja…

【PowerDesigner】PGSQL反向工程过程已中断

问题 反向工程过程已中断,原因是某些字符无法通过ANSI–&#xff1e;UTF-16转换进行映射。pg导入sql时报错&#xff0c;一查询是power designer 反向工程过程已中断&#xff0c;某些字符无法通过ANSI–>UTF-16转换进行映射&#xff08;会导致数据丢失&#xff09; 处理 注…

【LeetCode】热题100 刷题笔记

文章目录 T1 两数之和T49 字母异位词分组常用小技巧 T1 两数之和 链接&#xff1a;1. 两数之和 题目&#xff1a; 【刷题感悟】这道题用两层for循环也能做出来&#xff0c;但我们还是要挑战一下时间复杂度小于 O ( n 2 ) O(n^2) O(n2)的解法&#xff0c;不能因为它是第一道 …

docker部署实用的运维开发手册

下载镜像 docker pull registry.cn-beijing.aliyuncs.com/wuxingge123/reference:latestdocker-compose部署 vim docker-compose.yml version: 3 services:reference:container_name: referenceimage: registry.cn-beijing.aliyuncs.com/wuxingge123/reference:latestports:…

u盘插在电脑上显示要格式化磁盘怎么办

咨询&#xff1a;“U盘插入电脑&#xff0c;提示需要先格式化 才可使用。对于此种情况&#xff0c;在不需要格式化的情况下&#xff0c;是否可以恢复U盘内容&#xff1f;谢谢” 当我们尝试将U盘插入电脑时&#xff0c;有时会遇到一个令人困惑的提示&#xff1a;电脑要求我们格式…

【总结】在嵌入式设备上可以离线运行的LLM--Llama

文章目录 Llama 简介运用另一种&#xff1a;MLC-LLM 一个令人沮丧的结论在资源受限的嵌入式设备上无法运行LLM&#xff08;大语言模型&#xff09;。 一丝曙光&#xff1a;tinyLlama-1.1b&#xff08;10亿参数&#xff0c;需要至少2.98GB的RAM&#xff09; Llama 简介 LLaMA…

数据处理库Pandas数据结构DataFrame

Dataframe是一种二维数据结构&#xff0c;数据以表格形式&#xff08;与Excel类似&#xff09;存储&#xff0c;有对应的行和列&#xff0c;如图3-3所示。它的每列可以是不同的值类型&#xff08;不像 ndarray 只能有一个 dtype&#xff09;。基本上可以把 DataFrame 看成是共享…

KIMI官方精选提示词,好牛的感觉啊啊啊!

晚上好&#xff0c;我是云桃桃。一个希望帮助更多朋友快速入门 WEB 前端的程序媛。 云桃桃 1枚程序媛&#xff0c;大专生&#xff0c;2年时间从1800到月入过万&#xff0c;工作5年买房。 分享成长心得。 255篇原创内容-公众号 后台回复“前端工具”可获取开发工具&#xff0…

vscode安装

&#x1f308;个人主页&#xff1a;Rookie Maker &#x1f3c6;&#x1f3c6;关注博主&#xff0c;随时获取更多关于IT的优质内容&#xff01;&#x1f3c6;&#x1f3c6; &#x1f600;欢迎来到小田代码世界~ &#x1f601; 喜欢的小伙伴记得一键三连哦 ૮(˶ᵔ ᵕ ᵔ˶)ა …