数据结构 - 栈

概述

计算机科学中,stack是一种线性的数据结构,只能在其一段添加和移除数据.

习惯来说,这一端称之为栈顶,另一端不能操作数据的称之为栈底,就如同生活中的一摞书

先提供一个接口:

public interface Stack <E>{/*** 向栈顶压入元素* @param value -- 待压入值* @returns:压入成功返回true,否则返回false**/boolean push(E value);/*** 从栈顶弹出元素* @Returns:栈非空返回栈顶元素,栈为空返回null**/E pop();/*** 返回栈顶元素,不弹出* @Returns:栈非空返回栈顶元素,栈为空返回null*/E peek();/*** 判断栈是否为空* @Returns:空返回true,否则返回false**/boolean isEmpty();/*** 判断栈已满* @Returns:满返回true,否则返回false**/boolean isFull();
}

链表实现:

import java.util.Iterator;public class LinkedListStack <E> implements Stack<E>,Iterable<E>{private int capacity;private int size;private Node<E>head = new Node<>(null,null);public LinkedListStack(int capacity){this.capacity = capacity;}@Overridepublic Iterator<E> iterator() {return new Iterator<E>() {Node<E> p = head.next;@Overridepublic boolean hasNext() {return p!=null;}@Overridepublic E next() {E value = p.value;p=p.next;return value;}};}
/*2->head -> 2 -> 1 ->null*/@Overridepublic boolean push(E value) {if(isFull()){return false;}head.next = new Node<>(value,head.next);size++;return true;}/*head -> 2 ->1 ->null*/@Overridepublic E pop() {if(isEmpty()){return null;}Node<E> first = head.next;head.next = first.next;size--;return first.value;}@Overridepublic E peek() {if(isEmpty()){return null;}return head.next.value;}@Overridepublic boolean isEmpty() {return head.next ==null;//也可以size==0}@Overridepublic boolean isFull() {return size==capacity;}//单向链表实现static class Node<E> {E value;Node<E>next;public Node(E value,Node<E>next){this.value = value;this.next = next;}}}

数组实现: 

import java.util.Iterator;public class ArrayStack<E> implements Stack<E>,Iterable<E> {private E[] array;private int top;//栈顶指针/*底           顶0   1   2   3a   b   c   dt数组实现跟链表实现的顶部是相反的为什么链表的栈顶在首节点?因为增删查改方便,如果放在链表尾部那每次增删查改都需要遍历为什么数组实现的栈顶在尾部,因为数组是顺序结构*/@SuppressWarnings("all")public ArrayStack(int capacity) {this.array = (E[])new Object[capacity];}@Overridepublic Iterator<E> iterator() {return new Iterator<E>() {int p = top;@Overridepublic boolean hasNext() {return p>0;}@Overridepublic E next() {E value = array[p - 1];p--;//array[--p];return value;}};}@Overridepublic boolean push(E value) {if(isFull()) {return false;}array[top] = value;top++;//array[top++] = value;return true;}@Overridepublic E pop() {if(isEmpty()){return null;}E value = array[top-1];top --;//array[--top];return value;}@Overridepublic E peek() {if(isEmpty()){return null;}return array[top-1];}@Overridepublic boolean isEmpty() {return top == 0;}@Overridepublic boolean isFull() {return top == array.length;}
}

应用

模拟如下方法调用:

public class Main {public static void main(String[] args) {System.out.println("main1");System.out.println("main2");method1();method2();System.out.println("main3");}public static void method1() {System.out.println("method1");method3();}public static void method2() {System.out.println("method2");}public static void method3() {System.out.println("method3");}
}
/*** main1* main2* method1* method3* method2* main3*/

 模拟实现:

public class CPU {static class Frame {int exit;public Frame(int exit) {this.exit = exit;}}static int pc = 1; // 模拟程序计数器 Program counterstatic ArrayStack<Frame> stack = new ArrayStack<>(100); // 模拟方法调用栈public static void main(String[] args) {stack.push(new Frame(-1));while (!stack.isEmpty()) {switch (pc) {case 1 -> {System.out.println("main1");pc++;}case 2 -> {System.out.println("main2");pc++;}case 3 -> {stack.push(new Frame(pc + 1));pc = 100;}case 4 -> {stack.push(new Frame(pc + 1));pc = 200;}case 5 -> {System.out.println("main3");pc = stack.pop().exit;}case 100 -> {System.out.println("method1");stack.push(new Frame(pc + 1));pc = 300;}case 101 -> {pc = stack.pop().exit;}case 200 -> {System.out.println("method2");pc = stack.pop().exit;}case 300 -> {System.out.println("method3");pc = stack.pop().exit;}}}}
}
/*** main1* main2* method1* method3* method2* main3*/

练习一下:

20. 有效的括号 - 力扣(LeetCode)

E01. 有效的括号-Leetcode 20

一个字符串中可能出现 [] (){} 三种括号,判断该括号是否有效

有效的例子

()[]{}
​
([{}])
​
()

无效的例子

[)
​
([)]
​
([]

思路

  • 遇到左括号, 把要配对的右括号放入栈顶

  • 遇到右括号, 若此时栈为空, 返回 false,否则把它与栈顶元素对比

    • 若相等, 栈顶元素弹出, 继续对比下一组

    • 若不等, 无效括号直接返回 false

  • 循环结束

    • 若栈为空, 表示所有括号都配上对, 返回 true

    • 若栈不为空, 表示右没配对的括号, 应返回 false

答案(用到了上面案例中的 ArrayStack 类)

public boolean isValid(String s) {ArrayStack<Character> stack = new ArrayStack<>(s.length() / 2 + 1);for (int i = 0; i < s.length(); i++) {char c = s.charAt(i);if (c == '(') {stack.push(')');} else if (c == '[') {stack.push(']');} else if (c == '{') {stack.push('}');} else {if (!stack.isEmpty() && stack.peek() == c) {stack.pop();} else {return false;}}}return stack.isEmpty();}

class Solution {public boolean isValid(String s) {if(s.isEmpty())return true;Stack<Character> stack=new Stack<Character>();for(char c:s.toCharArray()){if(c=='(')stack.push(')');else if(c=='{')stack.push('}');else if(c=='[')stack.push(']');else if(stack.empty()||c!=stack.pop())return false;}if(stack.empty())return true;return false;}
}
class Solution {
public:bool isValid(string s) {if(s.size() == 0){return 0;}stack<char> st;for(auto &ch: s){if(ch == '(' || ch == '{' || ch == '['){st.push(ch);//入栈}else{if(!st.empty()){if(ch == ')'){if(st.top() != '('){return false;}st.pop();}else if(ch == '}'){if(st.top() != '{'){return false;}st.pop();}else if(ch == ']'){if(st.top() != '['){return false;}st.pop();}}else{return false;}}}return st.empty();}
};
E02-后缀表达式求值 

LCR 036. 逆波兰表达式求值 - 力扣(LeetCode)

import java.util.LinkedList;public class Main {/*逆波兰表达式也称为后缀表达式,即把运算符写在后面从左向右进行计算不必考虑运算优先级,即不用包含括号/     //     //     //     //     //  9  /------"2"  1 + 3 + *1+2  中缀表达式1 2 + 后缀表达式LinkedList里面也实现了栈*/public int evalRPN(String[] tokens) {LinkedList<Integer> numbers = new LinkedList<>();for (String t : tokens) {switch (t) {case "+" -> {Integer b = numbers.pop();Integer a = numbers.pop();numbers.push(a + b);}case "-" -> {Integer b = numbers.pop();Integer a = numbers.pop();numbers.push(a - b);}case "*" -> {Integer b = numbers.pop();Integer a = numbers.pop();numbers.push(a * b);}case "/" -> {Integer b = numbers.pop();Integer a = numbers.pop();numbers.push(a / b);}default -> numbers.push(Integer.parseInt(t));}}return numbers.pop();}}
E-03中缀表达式转后缀

反编译 

c = a + b

看不懂也没有关系,反正编译器会讲中缀表达式转换为后缀表达式

import java.util.LinkedList;/*** 中缀表达式转后缀*/
public class E03InfixToSuffix {//    public static void test(){
//        int a = 1;
//        int b =2;
//        int c = a+ b;
//    //在编译成class文件的时候就是把中缀表达式转换为了后缀表达式
//        //先让程序运行一次,目的是让程序生成字节码文件
//    }/*思路这是一个栈/   //   //   //   /----a+b      ab+a+b-c   ab+c-a+b*c   abc*+(a+b)*c  ab+c*(a+b*c-d)*e   abc*+d-e*a*(b+c)       abc+*1.遇到非运算符 直接拼串2.遇到 + - *  /- 它的优先级比栈顶运算符高,入栈- 否则把栈里优先级>=它 的都出栈, 它再入栈3.遍历完成,栈里剩余运算符依次出栈4.带()- 左括号直接入栈,左括号优先设置为0- 右括号就把栈里到左括号为止的所有运算符出栈*/public static void main(String[] args) {System.out.println(infixToSuffix("a+b"));System.out.println(infixToSuffix("a+b-c"));System.out.println(infixToSuffix("a+b*c"));System.out.println(infixToSuffix("a*b-c"));System.out.println(infixToSuffix("(a+b)*c"));System.out.println(infixToSuffix("a*(b+c)"));System.out.println(infixToSuffix("a+b*c+(d*e*f)*g"));}/*** 计算运算符优先级* @param c* @return*/static int priority(char c){return switch (c) {case '*','/'->2;case '+','-'->1;case '(' ->0;default->throw new IllegalArgumentException("不合法的运算符:"+c);};}static String infixToSuffix(String exp){LinkedList<Character>stack = new LinkedList<>();//栈StringBuilder sb = new StringBuilder(exp.length());//拼接for (int i = 0; i < exp.length(); i++) {char c = exp.charAt(i);switch (c) {case '+' ,'-','*','/'->{if(stack.isEmpty()){stack.push(c);}else{if (priority(c) >priority(stack.peek())) {stack.push(c);}else{while(!stack.isEmpty()&&priority(stack.peek())>=priority(c)){sb.append(stack.pop());}stack.push(c);}}}case '('->{stack.push(c);}case ')'->{while(!stack.isEmpty()&&stack.peek()!='('){sb.append(stack.pop());}stack.pop();}default ->{sb.append(c);}}}while(!stack.isEmpty()){sb.append(stack.pop());}return sb.toString();}
}
E04Leetcode232

232. 用栈实现队列 - 力扣(LeetCode)

class MyQueue {ArrayStack<Integer>s1 =new ArrayStack<>(100);ArrayStack<Integer>s2 =new ArrayStack<>(100);public void push(int x){//向队列尾添加s2.push(x);}public int pop(){if(s1.isEmpty()){while(!s2.isEmpty()){s1.push(s2.pop());}}return s1.pop();}public int peek(){if(s1.isEmpty()){while(!s2.isEmpty()){s1.push(s2.pop());}}return s1.peek();}public boolean empty(){return s1.isEmpty()&&s2.isEmpty();}static class ArrayStack<E>{private E[] array;private int top;//栈顶指针public ArrayStack(int capacity) {this.array = (E[])new Object[capacity];}public boolean push(E value) {if(isFull()){return false;}array[top++]=value;return true;}public E pop() {if(isEmpty()){return null;}E value = array[top - 1];top--;return value;}public E peek() {if(isEmpty()){return null;}E value = array[top - 1];return value;}public boolean isEmpty() {return top==0;}public boolean isFull() {return top==array.length;}}
}/*** Your MyQueue object will be instantiated and called as such:* MyQueue obj = new MyQueue();* obj.push(x);* int param_2 = obj.pop();* int param_3 = obj.peek();* boolean param_4 = obj.empty();*/

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

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

相关文章

✌粤嵌—2024/4/18—旋转链表✌

代码实现&#xff1a; 方法一&#xff1a;在原链表中找到旋转之后的首尾&#xff0c;改变指向 /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/ struct ListNode* rotateRight(struct ListNode *head, int k) {i…

线程安全问题的原因和解决方案

目录 原因分析 解决线程安全问题——加锁 synchroized&#xff08;&#xff09; 死锁 死锁的四个必要条件 线程安全是指多个线程同时访问共享资源时&#xff0c;不会产生不正确的结果。线程安全问题的主要原因是多个线程对共享数据进行读写操作时的并发性。这可能导致竞态…

制作直通网线和交叉网线

制作直通网线和交叉网线 1. 网络直通线2. 网络交叉线References 双绞线的连接方法有两种&#xff1a;直通连接和交叉连接 。 直通连接是将双绞线的两端分别都依次按白橙、橙、白绿、蓝、白蓝、绿、白棕、棕色的顺序 (国际 EIA/TIA 568B 标准) 压入 RJ45 水晶头内。这种方法制作…

壁纸、软件、电子书、音乐资源、数据库资源,囤一囤

资源网站我真的有很多&#xff01;&#xff01;下面这十几个都是壁纸资源、软件资源、电子书资源、音乐资源、数据库资源等等&#xff0c;感兴趣的囤一囤&#xff01; 一、壁纸资源 1、PEXELS 网址&#xff1a; https://www.pexels.com/zh-cn/ 一个专门分享无版权图片的网站…

Windows突然蓝屏解决办法

Windows突然蓝屏&#xff0c;然后重复开机没有用&#xff0c;但是能进入bios系统&#xff0c;证明内存和磁盘没事&#xff0c;用大白菜制作了PE系统盘制作过程&#xff08;之前一直都是用官方镜像制作&#xff0c;但是发现用大白菜制作可以对系统之前的磁盘里面重要的信息拷贝到…

Python用于比较数据结构并生成差异报告的工具库之data-diff使用详解

概要 Python的data-diff库是一个用于比较数据结构并生成差异报告的工具。它可以处理各种数据类型,如字典、列表、集合等,使得开发者能够快速识别数据之间的差异。 安装 通过pip可以轻松安装data-diff: pip install data-diff特性 支持多种数据类型:能够比较字典、列表、…

tokio 学习

Rust Async 异步编程 简易教程 理解tokio核心(1): runtime Rust 中的异步编程 Rust 中的 async 和线程 OS 线程&#xff1a; 适用于少量任务&#xff0c;有内存和 CPU 开销&#xff0c;且线程生成和线程间切换非常昂贵线程池可以降低一些成本允许重用同步代码&#xff0c;…

新手做抖音小店,最易爆单的几大类目分享,抓紧收藏!

大家好&#xff0c;我是电商糖果 新手做抖店没有经验&#xff0c;不了解市场&#xff0c;很多人都担心类目选错了&#xff0c;很难起店。 毕竟电商行业有一句话&#xff0c;类目大于一切&#xff0c;选择大于努力。 类目没有选对&#xff0c;再折腾也没用。 糖果做抖音小店…

eclipse配置SVN和Maven插件

3、 安装SVN插件 使用如下方法安装 Help–Install New Software 注意&#xff1a;目前只能安装1.8.x这个版本的SVN&#xff0c;如果使用高版本的SVN&#xff0c;在安装SVN和maven整合插件的时候就会报错&#xff0c;这应该是插件的bug。 点击Add name: subclipse location…

五款3dmax常用插件推荐(含云渲染工具)

在三维建模和动画设计领域&#xff0c;3ds Max软件因其强大功能和灵活性而广受欢迎。为了进一步提升工作效率和创作质量&#xff0c;有许多插件可供选择。本文推荐五款常用3ds Max插件&#xff0c;帮助你更好实现复杂的模型和动效创作。 五款3dmax常用插件推荐 1、Kitchen Cab…

Linux gcc 6

本章开始学习工具 什么是工具&#xff1f; 本质也是指令 yum 命令 小火车 sudo yum install sl&#xff08;安装sl&#xff09; sudo yum install -y sl //直接yes就不提示了 yum list //将yum源上的软件都穷举出来 yum search sl //结果不友好&#xff0c;不推荐 yum lis…

活动报名 | 如何进行全增量一体的异构数据库实时同步

伴随着新技术的不断涌现&#xff0c;市场竞争也在不断开辟新的角斗场——新的业务需求&#xff0c;新的应用设想都在这里迸发。 面对如此日新月异的竞争环境&#xff0c;企业的当务之急&#xff0c;是为新应用扎根准备好随时可取、准确一致的高质量数据土壤。在这样的背景下&a…

(二十八)Flask之wtforms库【上手使用篇】

目录&#xff1a; 每篇前言&#xff1a;用户登录验证&#xff1a;用户注册验证&#xff1a;使用示例&#xff1a; 抽象解读使用wtforms编写的类&#xff1a;简单谈一嘴&#xff1a;开始抽象&#xff1a; 每篇前言&#xff1a; &#x1f3c6;&#x1f3c6;作者介绍&#xff1a;【…

Docker 磁盘占用过多问题处理过程记录

一、问题描述 突然发现服务器磁盘使用超过95%了&#xff08;截图时2.1 和 2.2 已经执行过了&#xff09; 二、问题分析与解决 2.1&#xff0c;docker 无用镜像占用磁盘 # 使用 docker images 查看服务的镜像 docker images# 可以手动删除一些很大不用的 docker rmi ***## 也…

一秒内传输50万对纠缠光子?!纽约市量子网络刷新纪录

量子网络技术行业的领军企业Qunnect宣布&#xff0c;在纽约市的GothamQ网络上&#xff0c;其偏振量子比特的传输性能刷新了纪录。Qunnect利用现有的商用光缆实现了每秒传输50万对高保真度纠缠光子的速率&#xff0c;且该网络的正常运行时间超过了99%。 纽约34公里长的GothamQ量…

服务器数据恢复—RAID5故障导致SAP+oracle数据丢失的数据恢复案例

服务器存储数据恢复环境&#xff1a; 某品牌服务器存储中有一组由6块SAS硬盘组建的RAID5阵列&#xff0c;其中有1块硬盘作为热备盘使用。上层划分若干lun&#xff0c;存放Oracle数据库数据。 服务器存储故障&分析&#xff1a; 该RAID5阵列中一块硬盘出现故障离线&#xff0…

开启Three.js之旅(会持续完善)

文章目录 Three.js必备构建项目场景Scene相机CameraPerspectiveCamera 渲染器WebGLRendererCSS3DRenderer 灯光LightAmbientLightDirectionalLight 平行光PointLight 加载器CacheFileLoaderLoaderGLTFLoaderRGBELoaderTextureLoader 材质MetarialMeshBasicMaterialMeshLambertM…

k8s集群资源编排清单文件解读

1、YAML 文件概述 k8s集群中对资源管理和资源对象编排部署都可以通过声明样式&#xff08;YAML&#xff09;文件来解决&#xff0c;也就是可以把需要对资源对象操作编辑到 YAML 格式文件中&#xff0c;我们把这种文件叫做资源清单文件&#xff0c;通过 kubectl 命令直接使用资源…

原子的内部结构

原子非常神奇&#xff0c;花时间思考它是非常有价值的。尽管传统的太阳系示意图存在致命的缺点&#xff0c;但我们还是可以局部应用于原子。 首先&#xff0c;原子与太阳系具有相似性一原子的中心质量大&#xff0c;外部质量小。我们用最简单的氢原子做分析&#xff0c;氢原子…

辽宁梵宁教育课程概览:打造职场新人的设计技能利器

随着数字化时代的快速发展&#xff0c;设计技能在职场中的重要性日益凸显。对于职场新人而言&#xff0c;掌握优秀的设计能力不仅有助于个人职业发展&#xff0c;更能为企业创造更多价值。辽宁梵宁教育&#xff0c;作为一所致力于培养职场新人设计技能的培训机构&#xff0c;以…