数据结构——栈的实现(java实现)与相应的oj题

文章目录

  • 一 栈
    • 栈的概念:
    • 栈的实现:
    • 栈的数组实现
        • 默认构造方法
        • 压栈
        • 获取栈元素的个数
        • 出栈
        • 获取栈顶元素
        • 判断当前栈是否为空
    • java提供的Stack类
      • Stack实现的接口:
    • LinkedList也可以当Stack使用
    • 虚拟机栈,栈帧,栈的三个概念
  • 二 栈的一些算法题:
    • (1) 逆序打印单链表。
    • (2)[括号匹配](https://leetcode-cn.com/problems/valid-parentheses)
    • (3)[逆波兰表达式求值](https://leetcode-cn.com/problems/evaluate-reverse-polish-notation/)
      • 逆波兰表达式
    • (4) [出入栈次序匹配](https://www.nowcoder.com/practice/d77d11405cc7470d82554cb392585106?tpId=13&&tqId=11174&rp=1&ru=/activity/oj&qru=/ta/coding-interviews/question-ranking)
    • (5)[最小栈](https://leetcode-cn.com/problems/min-stack/)
    • 总结:


一 栈

栈的概念:

栈也是一种线性表,栈只允许在表的一端进行插入与删除操作,所以栈中数据的特征的先进后出(先进来的后出去)。
栈顶:是栈进行插入与删除操作的表的一端
栈底:不允许插入删除操作的一端
压栈:将数据插入到栈中
出栈:将数据移除栈
在这里插入图片描述

栈的实现:

栈的底层可以由数组实现,也可以由链表实现
栈由数组实现时,栈的压栈与出栈的时间复杂度均为O(1)。
栈由单链表实现时,
如果采用尾插法,压栈操作时间复杂度为O(n),如果有last指针,则
压栈时间复杂度为O(1),但是出栈的时间复杂度一定为O(n)。
如果采用头插法,则压栈与出栈的时间复杂度均为O(1).
栈由双链表实现时,不论采用头插法与尾插法,时间复杂度均为O(1)。

栈的数组实现

当栈使用数组实现时,栈的插入与删除操作,时间复杂度均为O(1);

public class MyStack {static   int  DEFAULT_SIZE  = 10; //设置默认的数组大小private   int [] element ;        //实现栈的数组int usedsize = 0 ;                //栈中有效元素的个数//默认构造方法public MyStack() {}//入栈public void push(int val) {}//出栈public int pop() {}//获取栈顶元素 但是不删除public int peek() { }//获取栈元素个数public int size(){} //判空public boolean isEmpty() { }       
}
默认构造方法

默认申请10个空间

public MyStack(){this.element = new int[10];}
压栈

思想:先判断栈满没满,如果满了则扩容,然后进行压栈

  public void push(int data){//先判断栈是否有空间if(usedsize==element.length){//如果没有空间//则扩容this.element = Arrays.copyOf(element,2*element.length);}//保证空间后this.element[usedsize++] = data;}
获取栈元素的个数

思想:直接返回usedsize

 public int size(){return usedsize;}
出栈

思想:先判断栈是否为空,为空则抛出异常,不为空,则返回栈顶元素值,并且usedsize-1.

  public int pop(){//要判断栈是否为空,如果为空,则退出try{if (isEmpty()) {//2. 问题出现,构造参数的形参问题,super()调用父类的构造方法throw new EmptyException("EmptyException异常报错");}}catch (EmptyException e){e.printStackTrace();}int val =   this.element[usedsize-1];usedsize -- ;return val;}
获取栈顶元素

思想:与出栈逻辑相同,只是usedsize值不需-1 。

 public int  peek(){try{if (isEmpty()) {throw new EmptyException("EmptyException异常报错");}}catch (EmptyException e){e.printStackTrace();}return    this.element[usedsize-1];}
判断当前栈是否为空

思想:直接判断usedsize 是否为0即可。

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

java提供的Stack类

在这里插入图片描述

Stack实现的接口:

在这里插入图片描述

  接口说明   1.  继承Cloneable接口支持克隆其他接口,暂时还没搞明白,以后更新补充

LinkedList也可以当Stack使用

java提供的LinkedList类也可以当做栈来使用,LinkedList的方法列表如下:
在这里插入图片描述

public class Test {public static void main(String[] args) {LinkedList<Integer> stack =  new LinkedList<>();stack.push(5);stack.push(2);stack.pop();stack.pop();stack.pop();}
}

在这里插入图片描述

虚拟机栈,栈帧,栈的三个概念

虚拟机栈是JVM中的一块内存。
栈帧是为一个方法,函数分配的内存。
栈是一种数据结构。

二 栈的一些算法题:

(1) 逆序打印单链表。

采用递归的方法:

// 递归方式
void printList(Node head){if(null != head){printList(head.next);System.out.print(head.val + " ");}
}

采用栈的方法:

void printList(Node head){if(null == head){return;}Stack<Node> s = new Stack<>();// 将链表中的结点保存在栈中Node cur = head;while(null != cur){s.push(cur);cur = cur.next;}
// 将栈中的元素出栈while(!s.empty()){System.out.print(s.pop().val + " ");}
}

(2)括号匹配

题解:1 . 对于这个题无法直接看出其数学模型,必须先画图,列出各种情况,再判断
在这里插入图片描述
从图中可以分析出,要实现判断括号匹配

  1. 就要使得每一个左括号和右括号能够与对应位置的右括号进行匹配判断
  2. 且当所有的左括号(右括号)判断完时,其对应的右括号(左括号)也判断完毕,即满足左括号个数与右括号个数相当的情况。
  3. 如果第一个括号是右括号,说明此括号没有对应的左括号,说明一定为字符串一定括号不匹配。

实现思想:遍历字符串,遇到左括号则存入栈中,遇到右括号则与栈顶元素比较,相匹配,则继续循环,如果不匹配或栈为空,则返回false。

class Solution1 {public boolean isValid(String s) {Stack <Character> stack = new Stack<>();//采用for循环,这样可以找到字符串中的字符for(int i =0;i<s.length();i++) {char ch = s.charAt(i);if (ch == '{' || ch == '[' || ch == '(') {//问题,java提供的栈是否需要手动扩容?stack.push(ch);} else {//如果是右括号的内容if (stack.isEmpty()) {return false;} else {char ch2 = stack.peek();   //当获取栈顶元素时,栈可能为空//栈区不能为空if (((ch == '}' && ch2 == '{') || (ch == ']' && ch2 == '[') || (ch == ')' && ch2 == '('))) {//说明匹配,//将栈顶的元素去除stack.pop();} else {//如果不匹配,情况1 如果栈中还没有左括号,则一定不匹配,return false;}}}}// 如果栈表为空,说明匹配完毕if(stack.isEmpty()){return true;}return false;}
}

(3)逆波兰表达式求值

逆波兰表达式

逆波兰表达式即后缀表达式,后缀表达式是由中缀表达式转换而成。
所谓中缀表达式即我们平常所写的±*/的算式
我们平常所写的中缀表达式中是有优先级的,即先乘除,后加减,有括号先算括号里面的
但是计算机是不能够识别优先级的,为了能够使计算机计算,我们将中缀表达式的规则
表达成后缀表达式的形式,这样计算机便能够计算算式。

中缀表达式转换成后缀表达式的的规则:

  1. 先将中缀表达式中能够加括号的部分都加上括号
  2. 然后将所有的运算符移到所在 最近扩号之外。
  3. 然后去除掉所有括号即得到后缀表达式。

后缀表达式的运算规则:
遍历整个表达式,遇到运算符时,则将运算符前面的两个数作为操作数计算
得出的结果替代两个操作数,然后继续遍历表达式,循环上次操作。

在这里插入图片描述
本题:只是要求按照后缀表达式的规则计算结果
实现思想:遍历表达式,遇到操作数即将操作数压入栈中,遇到运算符,则进行两次出栈
,获取两个操作数进行计算(需要注意的是第一次出栈的是右操作数,第二次出栈的是左操作数)
然后将计算的结果再进行压栈,然后循环此操作。

class Solution {public int evalRPN(String[] tokens) {//创建一个栈,创建栈时不需要考虑栈的空间大小Stack<Integer> stack = new Stack<>();//采用foreach进行遍历栈for (String str : tokens) {if (!isOperator(str)) {int a = Integer.parseInt(str);stack.push(a);} else {int val2 = stack.pop();int val1 = stack.pop();//如果为运算符switch (str) {case "+" : stack.push(val1 + val2);break;case "-" :  stack.push(val1 - val2);break;case "*" : stack.push(val1 * val2);break;case "/" : stack.push(val1 / val2);break;}}}return stack.peek();}

总结
1. 字符串形式的运算符不能直接转换成运算符
2. 后缀表达式先进栈的是左操作数,后进栈的是右操作数,当我们需要出栈时,第一次获取栈顶元素是右操作数,第二次获取栈顶元素才是左操作数。

(4) 出入栈次序匹配

在这里插入图片描述

class Solution2{public boolean IsPopOrder (int[] pushV, int[] popV) {// write code hereStack<Integer> stack = new Stack<>();int j = 0;for(int i = 0; i< pushV.length;i++) {stack.push(pushV[i]);while(!stack.empty() && j < popV.length &&stack.peek() == popV[j]) {stack.pop();j++;}}return stack.empty();}
}

(5)最小栈

题解:
如果只用一个栈的话,我们不可能实现题目的要求,只有能将栈的最小值时刻储存起来才能实现题目的要求。因此我们实现两个栈,一个栈用于存储数据,另一个最小栈用于存放栈当前的最小值。

在这里插入图片描述实现思想:入栈的规则:

  1. 普通栈一定要放,最小栈如果为空,或者栈顶元素小于压入的数据,则放入最小栈中
  2. 如果压入的数据与最小栈栈顶元素相当,也放入最小栈中。(因为最小栈中的元素必须与普通栈的最小值保持同步即必须与出栈的规则相匹配)。
    出栈的规则:
    如果普通栈的栈顶元素与最小栈栈顶元素相同,则最小栈也需要出栈。
class MinStack {//创建两个栈Stack <Integer> stack  =  new Stack<>(); //普通栈Stack <Integer> minStack = new Stack<>();//最小栈public MinStack() {}
public void push(int val) {//压栈,压入数据//普通栈一定要压入stack.push(val);//然后判断最小栈是否压入if(minStack.empty()){minStack.push(val);}else{if(val<=minStack.peek()){minStack.push(val);}}}public void pop() {//出栈//普通栈一定出栈int val =  stack.pop();//最小栈出栈://如果两栈的栈顶元素相同,则出栈if(val == minStack.peek()){minStack.pop();}}public int top() {//获取栈顶元素if(!stack.empty()){return stack.peek();}return -1 ;}public int getMin() {if(minStack.empty()){return -1;}return minStack.peek();}}

总结:

在使用栈时,最常用的运用是根据栈先进后出的特性,将一段有序的数据转为逆序后,再进行操作使用。

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

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

相关文章

JetBrains IDE 使用git进行多人合作开发教程

以下DEMO可以用于多人共同开发维护一个项目时&#xff0c;使用Git远程仓库的实践方案 分支管理 dev&#xff1a;开发分支test&#xff1a;测试分支prod&#xff1a;生成分支 个人开发也最起码有一个masterdev&#xff0c;作为主分支和当前开发分支。master永远是稳定版本&am…

花几千上万学习Java,真没必要!(十九)

1、StringBuilder&#xff1a; 测试代码1&#xff1a; package stringbuilder.com; import java.util.ArrayList; import java.util.List; public class StringBuilderExample { public static void main(String[] args) { // 初始化StringBuilder StringBuilder sb n…

腾讯会议产品策划的成长之路:从万字文档到功能落地的实战经验

腾讯会议产品策划的成长之路&#xff1a;从万字文档到功能落地的实战经验 在腾讯会议的产品团队中&#xff0c;有这样一位产品策划&#xff0c;他以其出色的逻辑思维、全局观念以及扎实的执行力&#xff0c;在团队中发挥着举足轻重的作用。他就是林陪同&#xff0c;一个自称“会…

css font 优化

文章目录 使用 font-display 控制字体加载预加载关键字体选择合适的字体文件类型按需创建字体文件HTTP 缓存优化 使用 font-display 控制字体加载 避免字体加载导致的空白 block&#xff1a;浏览器在短暂的阻塞期内不显示任何文本&#xff0c;直到字体加载完成。这可能导致页…

JAVA进阶学习12

文章目录 一、File类1.1 File对象的构造1.2 File对象的常见方法判断功能的方法获取功能的方法绝对路径和相对路径创建删除功能的方法 1.3 File的常用遍历方法1.4 File获取并遍历的其他方法1.5 用法举例二、IO流2.1 IO的分类2.2 字节流的方法概述2.2.1 FileOutputStream2.2.2 Fi…

如何配置Memcached以减少对数据库的直接访问

如何配置Memcached以减少对数据库的直接访问 1. 引言 在现代应用程序中&#xff0c;数据库通常是性能瓶颈的主要来源之一。通过使用Memcached&#xff0c;开发者可以显著减少数据库的负载&#xff0c;提高应用程序的响应速度。本文将详细介绍如何配置Memcached&#xff0c;以…

UE4-字体导入

一.字体导入 方法一&#xff1a; 然后通过导入将自己想要的字体导入到项目中&#xff0c;也可以直接将我们放在桌面的字体直接拖入到我们的内容浏览器中。 但是要注意想要发售游戏的话不可以这样导入微软的字体&#xff0c;因为Windows自带基本都有版权&#xff0c;所以最…

odoo17创建一个默认UI视图

XML 数据文件 当要加载的数据具有简单格式时&#xff0c;CSV 格式很方便。当格式更复杂时&#xff08;例如&#xff0c;加载视图或电子邮件模板的结构&#xff09;&#xff0c;我们使用 XML 格式。例如&#xff0c;此帮助字段包含 HTML 标记。虽然可以通过 CSV 文件加载此类…

明星应援系统小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;线上应援管理&#xff0c;线下应援管理&#xff0c;应援物品管理&#xff0c;购买订单管理&#xff0c;集资应援管理&#xff0c;集资订单管理&#xff0c;市集订单管理&#xff0…

极致竞争思维

老板请了几个毕业生&#xff0c;培训了一年&#xff0c;他们现在对业务的熟悉程度比我都熟悉多了&#xff0c;只是基本功不扎实&#xff0c;做出来的东西有很多问题。 老板请我来&#xff0c;给了我一个硬件总监的位置&#xff0c;实际上是要对他的整个系统做出诊断。 也是难为…

【QT】线程控制和同步

目录 概述 QThread常用API 线程使用 创建一个QThread的子类 主线程启动线程 线程安全 互斥锁 QMutex 使用示例&#xff1a;两个线程一个共享静态变量进行 线程子类创建 主线程调用 QMutexLocker 条件变量 信号量 概述 在 Qt 中&#xff0c;多线程的处理⼀般是…

【CSS in Depth 2 精译_020】3.3 元素的高度

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第一章 层叠、优先级与继承&#xff08;已完结&#xff09; 1.1 层叠1.2 继承1.3 特殊值1.4 简写属性1.5 CSS 渐进式增强技术1.6 本章小结 第二章 相对单位&#xff08;已完结&#xff09; 2.1 相对…

【proteus经典实战】定时器控制交通灯指示灯

一、简介 基于8051系列单片机实现&#xff0c;旨在模拟一个简单的交通灯系统&#xff0c;实现红、黄、绿灯的交替亮灭。使用了特殊功能寄存器&#xff08;SFR&#xff09;和位操作来控制硬件&#xff0c;使用定时器0的中断功能来控制交通灯信号的切换。通过软件控制&#xff0…

解决selenium打印保存为PDF时图片未加载成功的问题

使用selenium打印网页时&#xff0c;如果程序运行很快的话&#xff0c;可能会导致图片没有加载成功即进行了保存&#xff0c;出现这个问题最初的思考是在执行打印任务时使用js进行强制等待&#xff0c;后发现实现效果并不好。在加载页面时使用自动下滑的方式将网页拉到底&#…

uniapp动态计算并设置元素高度

<template><view><scroll-view id"sv-box" :scroll-y"true" :style"{height:navHeightpx}"></scroll-view><view id"btn-box"><button>取消</button><button>确认</button><…

Linux Vim教程(三):插入模式与命令模式

目录 1. Vim的基本模式介绍 2. 插入模式 2.1 进入插入模式 2.2 退出插入模式 2.3 插入模式下的快捷键 2.4 插入模式中的光标移动 3. 命令模式 3.1 进入命令模式 3.2 常用命令 3.3 搜索和替换 3.4 其他有用的命令 3.5 配置与优化 3.5.1 自动补全 3.5.2 自定义快捷…

【前后端联调】HttpMessageNotReadableException

【前后端联调】HttpMessageNotReadableException 01 问题描述 在前后端联调时产生的问题&#xff0c;关键是下面这句翻译JSON解析错误&#xff1a;无法构造“java.util.ArrayList”的实例 org.springframework.http.converter.HttpMessageNotReadableException: JSON parse …

记录贴-NGINX相关

链接: NGINX相关配置信息说明

在 CI/CD 中怎么使用 Docker 部署前端项目?

本项目代码已开源&#xff0c;具体见&#xff1a; 前端工程&#xff1a;vue3-ts-blog-frontend 后端工程&#xff1a;express-blog-backend 数据库初始化脚本&#xff1a;关注公众号程序员白彬&#xff0c;回复关键字“博客数据库脚本”&#xff0c;即可获取。 前言 在上一篇文…

Web Pages 表单

Web Pages 表单 介绍 Web pages 表单是现代网页设计中不可或缺的组成部分&#xff0c;它们允许用户与网站进行交互&#xff0c;提交信息&#xff0c;如注册、登录、反馈、预订等。表单的设计和功能对用户体验和网站的业务目标有着直接的影响。本文将深入探讨Web pages表单的各…