数据结构第06节:栈

栈(Stack)是一种后进先出(Last In First Out, LIFO)的数据结构,它只允许在一端,称为栈顶(Top),进行添加(Push)和移除(Pop)数据项的操作。栈常用于解决递归、回溯、函数调用等问题。

栈的基本操作包括:

  1. Push: 向栈顶添加一个元素。
  2. Pop: 移除栈顶元素,并返回它。
  3. Peek/Top: 返回栈顶元素但不移除它。
  4. IsEmpty: 检查栈是否为空。
  5. Size: 返回栈中的元素数量。

下面是使用Java实现栈的一个简单示例:

import java.util.EmptyStackException;public class Stack<T> {private static class StackNode<T> {private T data;private StackNode<T> next;public StackNode(T data) {this.data = data;}}private StackNode<T> top;private int size;public Stack() {top = null;size = 0;}public void push(T item) {StackNode<T> t = new StackNode<T>(item);t.next = top;top = t;size++;}public T pop() {if (isEmpty()) {throw new EmptyStackException();}T item = top.data;top = top.next;size--;return item;}public T peek() {if (isEmpty()) {throw new EmptyStackException();}return top.data;}public boolean isEmpty() {return top == null;}public int size() {return size;}
}

在这个Java实现中,我们使用了泛型(<T>),使得栈可以存储任何类型的数据。内部的StackNode类用于表示栈中的每个元素,它包含数据和指向下一个元素的链接。Stack类本身维护了一个指向栈顶的引用top,以及栈的大小size

使用这个栈类的方法如下:

public class Main {public static void main(String[] args) {Stack<Integer> stack = new Stack<>();stack.push(1);stack.push(2);stack.push(3);System.out.println("Top element is: " + stack.peek()); // 输出3while (!stack.isEmpty()) {System.out.println(stack.pop());}}
}

在这个例子中,我们创建了一个整数类型的栈,然后向栈中添加了几个元素。使用peek方法可以查看栈顶元素而不移除它,最后通过一个循环,使用pop方法来移除并打印所有元素,直到栈为空。

Demo1:实现一个简易的文本编辑器中的撤销(Undo)功能

在文本编辑器中,每当用户执行一个操作,比如插入或删除文本,这个操作就会被压入一个栈中。如果用户想要撤销最近的操作,编辑器就会从栈中弹出最近的一个操作并执行它的逆操作。

以下是使用Java实现文本编辑器中撤销功能的示例代码:

interface EditAction {void execute();  // 执行操作void undo();     // 撤销操作
}class TextEditor {private String text;private Stack<EditAction> undoStack;public TextEditor() {text = "";undoStack = new Stack<>();}public void type(String input) {// 保存当前文本状态以便撤销undoStack.push(new EditAction() {@Overridepublic void execute() {// 这里不需要实现,因为我们不会重新执行这个操作}@Overridepublic void undo() {// 撤销操作:删除最近输入的文本text = text.substring(0, text.length() - input.length());}});text += input;}public void undo() {if (!undoStack.isEmpty()) {EditAction action = undoStack.pop();action.undo();}}public String getText() {return text;}
}public class Main {public static void main(String[] args) {TextEditor editor = new TextEditor();editor.type("Hello");editor.type(" World");System.out.println(editor.getText());  // 输出 "Hello World"editor.undo();  // 撤销 " World"System.out.println(editor.getText());  // 输出 "Hello"editor.undo();  // 撤销 "Hello"System.out.println(editor.getText());  // 输出 ""}
}

在这个例子中,我们定义了一个EditAction接口,它包含executeundo方法。TextEditor类使用一个栈来存储编辑操作,以便可以撤销它们。type方法模拟用户在文本编辑器中输入文本,并将一个匿名内部类实例作为EditAction压入栈中,该实例实现了撤销最近输入文本的功能。undo方法从栈中弹出最近的EditAction并调用其undo方法来撤销操作。

这个简单的撤销功能展示了栈在实际应用中的一个典型用途,即维护一个操作的历史记录,以便可以按相反的顺序撤销它们。

Demo2:实现浏览器的前进和后退功能

浏览器历史记录可以通过两个栈来实现:一个用于存储后退历史(Back Stack),另一个用于存储前进历史(Forward Stack)。当用户访问一个新页面时,当前页面会被推入后退栈,如果用户点击后退按钮,页面会从后退栈中弹出并推入前进栈;如果用户点击前进按钮,页面会从前进栈中弹出并推回后退栈。

以下是使用Java实现浏览器历史记录功能的示例代码:

public class BrowserHistory {private Stack<String> backStack;private Stack<String> forwardStack;private String currentURL;public BrowserHistory() {backStack = new Stack<>();forwardStack = new Stack<>();currentURL = "Start Page";  // 假设初始页面是起始页}public void visit(String url) {backStack.push(currentURL);currentURL = url;forwardStack.clear();  // 清除前进栈,因为历史已经改变}public String back() {if (backStack.isEmpty()) {return "No pages to go back to.";}forwardStack.push(currentURL);currentURL = backStack.pop();return currentURL;}public String forward() {if (forwardStack.isEmpty()) {return "No pages to go forward to.";}backStack.push(currentURL);currentURL = forwardStack.pop();return currentURL;}public String getCurrentURL() {return currentURL;}
}public class Main {public static void main(String[] args) {BrowserHistory history = new BrowserHistory();System.out.println(history.getCurrentURL());  // 输出起始页面history.visit("https://www.google.com");history.visit("https://www.example.com");System.out.println(history.getCurrentURL());  // 输出 "https://www.example.com"history.back();System.out.println(history.getCurrentURL());  // 输出 "https://www.google.com"history.forward();System.out.println(history.getCurrentURL());  // 输出 "https://www.example.com"history.visit("https://www.anotherpage.com");System.out.println(history.getCurrentURL());  // 输出 "https://www.anotherpage.com"history.back();System.out.println(history.getCurrentURL());  // 输出 "https://www.google.com"}
}

在这个例子中,BrowserHistory类有两个栈:backStack用于存储后退历史,forwardStack用于存储前进历史。visit方法模拟用户访问新页面,将当前页面URL压入后退栈,并将新页面URL设置为当前URL,同时清空前进栈。back方法模拟用户点击后退按钮,将当前页面URL压入前进栈,并从后退栈中弹出之前的页面URL作为当前页面。forward方法模拟用户点击前进按钮,将当前页面URL压入后退栈,并从前进栈中弹出下一个页面URL作为当前页面。

这个例子展示了栈在模拟浏览器历史记录中的实用性,允许用户在访问过的页面之间前进和后退。

Demo3:表达式求值

使用栈可以方便地处理括号匹配和运算符优先级的问题。以下是一个使用栈进行基本算术表达式求值的Java实现:

import java.util.Stack;public class ExpressionEvaluator {public int evaluate(String expression) {Stack<Integer> numbers = new Stack<>();Stack<Character> operators = new Stack<>();String num = "";for (int i = 0; i < expression.length(); i++) {char c = expression.charAt(i);if (Character.isDigit(c)) {num += c;} else {if (!num.isEmpty()) {numbers.push(Integer.parseInt(num));num = "";}if (c == '(') {operators.push(c);} else if (c == ')') {while (!operators.isEmpty() && operators.peek() != '(') {numbers.push(applyOperation(numbers.pop(), numbers.pop(), operators.pop()));}operators.pop(); // Pop the '('} else if (isOperator(c)) {while (!operators.isEmpty() && hasHigherPrecedence(operators.peek(), c)) {numbers.push(applyOperation(numbers.pop(), numbers.pop(), operators.pop()));}operators.push(c);}}}if (!num.isEmpty()) {numbers.push(Integer.parseInt(num));}while (!operators.isEmpty()) {numbers.push(applyOperation(numbers.pop(), numbers.pop(), operators.pop()));}return numbers.pop();}private boolean isOperator(char c) {return c == '+' || c == '-' || c == '*' || c == '/';}private boolean hasHigherPrecedence(char op1, char op2) {return (op1 == '*' || op1 == '/') && (op2 == '+' || op2 == '-');}private int applyOperation(int b, int a, char op) {switch (op) {case '+': return a + b;case '-': return a - b;case '*': return a * b;case '/': return a / b;}return 0;}public static void main(String[] args) {ExpressionEvaluator evaluator = new ExpressionEvaluator();String expression = "3+5*(2-1)";System.out.println("Result: " + evaluator.evaluate(expression)); // 输出结果}
}

在这个例子中,ExpressionEvaluator类使用两个栈:numbers用于存储操作数,operators用于存储运算符。evaluate方法遍历表达式字符串,当遇到数字时将其累加到num字符串中,当遇到运算符或括号时,执行相应的操作。

  • 如果遇到左括号(,将其压入operators栈。
  • 如果遇到右括号),从栈中弹出运算符并执行相应的运算,直到遇到左括号。
  • 如果遇到运算符,检查栈顶运算符的优先级,如果当前运算符优先级更高或相同,则先执行栈中的运算。
  • 最后,如果栈中还有运算符,继续执行运算直到所有运算符都被处理完毕。

isOperator方法用于检查字符是否是运算符,hasHigherPrecedence方法用于比较两个运算符的优先级,applyOperation方法用于执行具体的运算。

这个例子展示了栈在处理带有括号的表达式求值中的实用性,能够有效地处理运算符优先级和括号匹配的问题。

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

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

相关文章

双曲方程初值问题的差分逼近(迎风格式)

稳定性: 数值例子 例一 例二 代码 % function chap4_hyperbolic_1st0rder_1D % test the upwind scheme for 1D hyperbolic equation % u_t + a*u_x = 0,0<x<L,O<t<T, % u(x,0) = |x-1|,0<X<L, % u(0,t) = 1% foundate = 2015-4-22’; % chgedate = 202…

SpringBoot 如何处理跨域请求?你说的出几种方法?

引言&#xff1a;在现代的Web开发中&#xff0c;跨域请求&#xff08;Cross-Origin Resource Sharing&#xff0c;CORS&#xff09;是一个常见的挑战。随着前后端分离架构的流行&#xff0c;前端应用通常运行在一个与后端 API 不同的域名或端口上&#xff0c;这就导致了浏览器的…

方法的用法

一.简介 目前为止我给出的所有的案例都是将代码放在main方法中&#xff0c;就会产生一些问题&#xff1a; 代码冗长&#xff0c;不利于维护变量过多&#xff0c;想不出那么多的变量名没有重用性 那么该如何解决呢&#xff1f; 我们可以编写功能性的代码块&#xff0c;来被ma…

华为DCN之:SDN和NFV

1. SDN概述 1.1 SDN的起源 SDN&#xff08;Software Defined Network&#xff09;即软件定义网络。是由斯坦福大学Clean Slate研究组提出的一种新型网络创新架构。其核心理念通过将网络设备控制平面与数据平面分离&#xff0c;从而实现了网络控制平面的集中控制&#xff0c;为…

【STM32 RTC实时时钟如何配置!超详细的解析和超简单的配置,附上寄存器操作】

STM32 里面RTC模块和时钟配置系统(RCC_BDCR寄存器)处于后备区域&#xff0c;即在系统复位或从待机模式唤醒后&#xff0c;RTC的设置和时间维持不变。因为系统对后备寄存器和RTC相关寄存器有写保护&#xff0c;所以如果想要对后备寄存器和RTC进行访问&#xff0c;则需要通过操作…

PHP校园论坛-计算机毕业设计源码08586

摘 要 本项目旨在基于PHP技术设计与实现一个校园论坛系统&#xff0c;以提供一个功能丰富、用户友好的交流平台。该论坛系统将包括用户注册与登录、帖子发布与回复、个人信息管理等基本功能&#xff0c;并结合社交化特点&#xff0c;增强用户之间的互动性。通过利用PHP语言及其…

14-15 为什么我们现在对阅读如此难以接受

写出来感觉很奇怪&#xff0c;但最近我感觉自己失去了阅读能力。长篇文本对我来说尤其具有挑战性。句子很难读完。更别提章节了。章节有很多段落&#xff0c;而段落又由许多句子组成。 啊。 即使在极少数情况下&#xff0c;我读完了一章&#xff0c;下一页上已经有另一章等着…

什么是自动气象站呢

自动气象站&#xff0c;作为现代气象观测的重要工具&#xff0c;已经深入到我们生活的各个领域&#xff0c;从气象预报到农业生产&#xff0c;再到环境保护&#xff0c;自动气象站都发挥着不可或缺的作用。 自动气象站&#xff0c;顾名思义&#xff0c;是一种能够自动收集、处理…

153. 寻找旋转排序数组中的最小值(中等)

153. 寻找旋转排序数组中的最小值 1. 题目描述2.详细题解3.代码实现3.1 Python3.2 Java 1. 题目描述 题目中转&#xff1a;153. 寻找旋转排序数组中的最小值 2.详细题解 如果不考虑 O ( l o g n ) O(log n) O(logn)的时间复杂度&#xff0c;直接 O ( n ) O(n) O(n)时间复杂…

基于Spring Boot的先进时尚室内管理系统

1 项目介绍 1.1 研究背景 随着21世纪信息技术革命的到来&#xff0c;互联网的普及与发展对人类社会的演变产生了深远影响&#xff0c;跨越了物质生活的丰盈边界&#xff0c;更深层次地滋养了人类的精神文化生活。在过去&#xff0c;囿于地理位置和技术条件的限制&#xff0c;…

【网络】网络基础(一)

网络基础&#xff08;一&#xff09; 文章目录 一、计算机网络背景1.1网络发展1.2认识“协议” 二、网络协议初识2.1OSI七层模型2.2OSI五层模型 三、网络传输基本流程3.1局域网通信3.2网络传输流程不跨子网的网络传输跨子网的网络传输 3.3网络中的地址管理IP地址MAC地址 一、计…

使用conda安装第三方包报错CondaSSLError

使用conda安装第三方包报错CondaSSLError 1. 报错信息2. 解决方法 1. 报错信息 错误描述&#xff1a;刚刚下载的 anaconda 在使用 conda 安装 pytorch 时报错&#xff08;CondaSSLError: OpenSSL appears to be unavailable on this machine. OpenSSL is required to download …

LeetCode题练习与总结:二叉树的后序遍历--145

一、题目描述 给你一棵二叉树的根节点 root &#xff0c;返回其节点值的 后序遍历 。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[3,2,1]示例 2&#xff1a; 输入&#xff1a;root [] 输出&#xff1a;[]示例 3&#xff1a; 输入&#xff1a…

2002-2022年各省老年人口抚养比(人口抽样调查)数据

2002-2022年各省老年人口抚养比(人口抽样调查)数据 1、时间&#xff1a;2002-2022年 2、指标&#xff1a;老年人口抚养比 3、来源&#xff1a;国家统计局、统计年鉴 4、范围&#xff1a;31省&#xff0c; 5、缺失情况&#xff1a;无缺失&#xff0c;其中2010年的值取2009、…

Swift 中强大的 Key Paths(键路径)机制趣谈(下)

概览 在上一篇博文 Swift 中强大的 Key Paths(键路径)机制趣谈(上)中,我们介绍了 Swift 语言中键路径机制的基础知识,并举了若干例子讨论了它的一些用武之地。 而在本文中我们将再接再厉,继续有趣的键路径大冒险,为 KeyPaths 画上一个圆满的句号。 在本篇博文中,您将…

JavaScript之深入对象,详细讲讲构造函数与常见内置构造函数

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;我是前端菜鸟的自我修养&#xff01;今天给大家详细讲讲构造函数与常见内置构造函数&#xff0c;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;原创不易&#xff0c;如果能帮助到带大家&#xff0c;欢迎…

笔记:Git学习之应用场景和使用经验

目标&#xff1a;整理Git工具的应用场景和使用经验 一、开发环境 Git是代码版本控制工具&#xff1b;Github是代码托管平台。 工具组合&#xff1a;VSCode Git 需要安装的软件&#xff1a;vscode、Git 其中vscode需要安装的插件&#xff1a;GitLens、Git History 二、应用…

Unity编辑器工具---版本控制与自动化打包工具

Unity - 特殊文件夹【作用与是否会被打包到build中】 Unity编辑器工具—版本控制与自动化打包工具&#xff1a; 面板显示&#xff1a;工具包含一个面板&#xff0c;用于展示软件的不同版本信息。版本信息&#xff1a;面板上显示主版本号、当前版本号和子版本号。版本控制功能…

单目行车测距摄像系统(单目测距-行车)

单目行车测距摄像系统是一种利用单个摄像头实现车辆行驶中前方障碍物距离测量的技术。该系统通过计算机视觉算法&#xff0c;能够实时分析摄像头捕捉的图像&#xff0c;精确计算出车辆与前方物体之间的距离&#xff0c;对于自动驾驶、高级驾驶辅助系统&#xff08;ADAS&#xf…

【探索Linux】P.36(传输层 —— TCP协议段格式)

阅读导航 引言一、TCP段的基本格式二、控制位详细介绍三、16位接收窗口大小⭕窗口大小的作用⭕窗口大小的限制⭕窗口缩放选项⭕窗口大小的更新⭕窗口大小与拥塞控制 四、紧急指针温馨提示 引言 在上一篇文章中&#xff0c;我们深入探讨了一种无连接的UDP协议&#xff0c;它以其…