栈(也被称作堆栈,一种遵循先进后出原则的数据结构)

2023-11-13

1. 栈(Stack)

栈(又被称作堆栈,但与堆不是同一个概念)是用来存放对象的一种特殊的容器,它是最基本的数据结构之一,遵循“先进后出(Last-in-first-out,LIFO)”的原则。

栈有两个端点,起始的一端被称作栈底,另一端被称作栈顶(可以添加新元素的一端),栈底固定,而栈顶浮动,且栈内元素的增减只能在栈顶实现。一般会用一个指针指向栈顶的位置,以方便入栈和出栈的操作。

入栈和出栈是栈的两个最基本的接口,分别代表向栈内添加或删除元素。

1.1 入栈(push)

我们可以往栈中添加对象,此操作被称为“入栈”,一般我们习惯用 push 表示将一个对象压至栈顶。

对于入栈操作而言,如果栈的容量是固定的,那入栈操作就可能会有栈溢出的风险,在实际编写代码时需要注意到这一点。

入栈操作

1.2 出栈(pop)

同样的也可以删除栈中的元素,此操作被称为“出栈”,一般习惯用 pop 表示将一个对象从栈顶移除。

对于出栈操作而言,存在“栈空”的风险,即进行出栈操作时,栈内已经没有元素了。

出栈操作

1.3 栈的抽象数据类型(栈ADT)

方法 功能描述
push(x) 若栈未满,则将对象x压至栈顶,否则报错
pop() 若栈非空,则将栈顶的对象移除,并将其返回,否则报错
getSize() 返回当前栈中对象的数目
isEmpty() 用于检测栈是否为空
top() 若栈非空,则返回栈顶的对象(但并不移除),否则报错

1.4 栈接口

/** 
* 栈接口
*/
public interface Stack {
	void push(Object o);
	Object pop() throws ExceptionStackEmpty;
	int getSize();
	boolean isEmpty(); 
	Object top() throws ExceptionStackEmpty;
}

可以使用官方的java.util.Deque接口(),里面给出了push()pop()等方法。

2. 利用数组实现栈

2.1 栈的实现

利用数组很容易就可以实现栈这种数据结构。我们可以定义一个容量为N的数组用于存放栈的元素,让此数组下标为0的位置为栈底,并用一个变量top指向当前的栈顶。

由于Java数组元素的下标都是从0开始的,可以将变量top初始化为-1(栈空)。具体实现如下所示:

public class ExceptionStackFull extends RuntimeException {

	public ExceptionStackFull(String error) {
		super(error);
	}

}
public class ExceptionStackEmpty extends RuntimeException {

	public ExceptionStackEmpty(String error) {
			super(error);
	}

}
/**
* 借助定长数组实现Stack接口 
*/
public class ArrayStack implements Stack {
	private static final int CAPACITY = 1024;
	private int capacity;
	private Object[] arrayStack; 
	private int top; // 栈顶元素的位置
	
	public ArrayStack() {
		this(CAPACITY); 
	}

	public ArrayStack(int capacity) {
		this.capacity = capacity;
		arrayStack = new Object[capacity];
		top = -1;
	} 
	
	@Override
	public int getSize() {
		return (top + 1);
	}

	@Override
	public boolean isEmpty() {
		return (top < 0);
	}

	// 栈的容量有限时入栈操作可能使栈溢出
	@Override
	public void push(Object obj) throws ExceptionStackFull {
		if (getSize() == capacity) {
			throw new ExceptionStackFull("意外:栈溢出");
		}
		// 先移动指向栈顶的变量top,再压入对象
		arrayStack[++top] = obj;
	} 
	
	@Override
	public Object top() throws ExceptionStackEmpty {
		if (isEmpty()) {
			throw new ExceptionStackEmpty("意外:栈空");
		}
		return arrayStack[top];
	}
	
	@Override
	public Object pop() throws ExceptionStackEmpty {
		Object elem;
		if (isEmpty()) {
			throw new ExceptionStackEmpty("意外:栈空");
		}
		elem = arrayStack[top];
		// 先移除对象,后移动指向栈顶的变量top
		arrayStack[top--] = null;
		return elem;
	}

}

2.2 利用数组实现栈的优势与缺点

  1. 优势:
    1) 实现简单
    2) 各方法的时间复杂度均为O(1)
  2. 缺点:
    1) 若数组容量为N,则空间复杂度为O(N),当栈中的元素较少时会造成空间的浪费
    2) 入栈操作会有栈溢出的风险

3. 利用单链表实现栈

3.1 栈的实现

为解决栈溢出和空间浪费的问题,我们可以用 “可变的数组” —— 链表来实现栈。

利用单链表也可以实现栈这一数据结构,具体实现如下:

/**
 * 单链表节点类
*/
public class Node {
	private Object element; // 数据对象
	private Node next; // 指向后继节点
	
	public Node() {
		this(null, null);
	}
	
	public Node(Object element, Node next) {
		this.element = element;
		this.next = next;
	}
	
	public Object getElement() {
		return element;
	}
	
	public Object setElement(Object element) {
		Object oldElem = element;
		this.element = element;
		return oldElem;
	}
	
	public Node getNext() {
		return next;
	}
	
	public void setNext(Node next) {
		this.next = next;
	}
}
/**
 * 借助单链表实现Stack接口
*/
public class LinkedListStack implements Stack {
	private Node top;
	private int size;
	
	public LinkedListStack() {
		top = null;
		size = 0;
	}

	@Override
	public int getSize() {
		return size;
	}

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

	@Override
	public Object top() throws ExceptionStackEmpty {
		if (isEmpty()) {
			throw new ExceptionStackEmpty("意外:栈空");
		}
		return top.getElement();
	}

	@Override
	public void push(Object obj) {
		Node node = new Node(obj, top);
		top = node;
		size++;
	}

	@Override
	public Object pop() throws ExceptionStackEmpty {
		if (isEmpty()) {
			throw new ExceptionStackEmpty("意外:栈空");
		}
		Object returnElement = top.getElement();
		top = top.getNext();
		size--;
		return returnElement;
	}

}

3.2 利用单链表实现栈的优势与缺点

  1. 优势:
    1) 栈中实际有n个元素,空间复杂度即为O(n),空间利用效率较高
    2) 入栈操作不会有栈溢出的风险
  2. 缺点:
    1) 较数组实现来说,再实现难度上略有增加
    2) 为保证所有方法的时间复杂度均为O(1),需要有一个变量由于记录栈中元素的数目,且需把单链表的首节点作为栈顶。

4. 栈的应用

4.1 Java 虚拟机(JVM)中的栈

Java 的每一个程序都要被编译为一个二进制指令序列,这些指令可以在一个特定的计算模型 ——Java 虚拟机(Java Virtual Machine, JVM)上执行。对于 JVM 的定义而言,栈这一数据结构也是至关重要的。

任一运行中的Java程序(更准确地说,应该是运行中的Java线程)都会配备一个私有的栈,称作Java方法栈(Java method stack)或简称Java栈(Java stack),用来记录各个方法在被调用过程中的局部变量等重要信息。

JVM 还设置了一个被称作程序计数器(Program counter)的变量PC,负责记录程序在 JVM 中运行时的当前位置。当方法 N 要调用方法 M 时,程序计数器当前的数值就会被存放在 N 的实例所 对应的帧中⎯⎯这样,待M执行完毕后,JVM才能知道应该返回到什么位置并继续执行下去。

Java方法栈的实例

上图是一个Java方法栈的实例,如图所示,JVM通过栈实现了方法的调用,同时将参数以值传递的方式传递给被调用的方法。

实际上,JVM 对栈的应用并不仅限于方法栈。在对算术表达式进行求值时,JVM 也使用了另一个栈——操作数栈(Operand stack)。

以“a+b”为例,为了计算其值,首先将 a 和 b 依次压入栈中,然后执行一条专门的指令。该指令要求将栈顶的两个元素弹出,对它们实施加法,并将结果重新压入栈中。

4.2 其他应用

除了在JVM中,栈在其它地方也有着广泛的应用,例如:

  1. 撤销操作
  2. 中断
  3. 实现一组数据的倒置
  4. 表达式中括号的匹配
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

栈(也被称作堆栈,一种遵循先进后出原则的数据结构) 的相关文章

  • JavaMail Gmail 问题。 “准备启动 TLS”然后失败

    mailServerProperties System getProperties mailServerProperties put mail smtp port 587 mailServerProperties put mail smtp
  • 如何将 Java 赋值表达式转换为 Kotlin

    java中的一些东西就像 int a 1 b 2 c 1 if a b c System out print true 现在它应该转换为 kotlin 就像 var a Int 1 var b Int 2 var c Int 1 if a
  • Java程序中的数组奇怪的行为[重复]

    这个问题在这里已经有答案了 我遇到了这个 Java 程序及其以意想不到的方式运行 以下程序计算 int 数组中元素对之间的差异 import java util public class SetTest public static void
  • Android Studio 在编译时未检测到支持库

    由于 Android Studio 将成为 Android 开发的默认 IDE 因此我决定将现有项目迁移到 Android studio 中 项目结构似乎不同 我的项目中的文件夹层次结构如下 Complete Project gt idea
  • 如何查找 Android 设备中的所有文件并将它们放入列表中?

    我正在寻求帮助来列出 Android 外部存储设备中的所有文件 我想查找所有文件夹 包括主文件夹的子文件夹 有办法吗 我已经做了一个基本的工作 但我仍然没有得到想要的结果 这不起作用 这是我的代码 File files array file
  • 在数据流模板中调用 waitUntilFinish() 后可以运行代码吗?

    我有一个批处理 Apache Beam 作业 它从 GCS 获取文件作为输入 我的目标是根据执行后管道的状态将文件移动到两个 GCS 存储桶之一 如果管道执行成功 则将文件移动到存储桶 A 否则 如果管道在执行过程中出现任何未处理的异常 则
  • 使用 ANTLR 为 java 源代码生成抽象语法树

    如何使用 ANTLR 从 java src 代码生成 AST 有什么帮助吗 好的 步骤如下 前往ANTLR站点 http www antlr org 并下载最新版本 下载Java g和JavaTreeParser g文件来自here htt
  • HDFS:使用 Java / Scala API 移动多个文件

    我需要使用 Java Scala 程序移动 HDFS 中对应于给定正则表达式的多个文件 例如 我必须移动所有名称为 xml从文件夹a到文件夹b 使用 shell 命令我可以使用以下命令 bin hdfs dfs mv a xml b 我可以
  • 无法理解 Java 地图条目集

    我正在看一个 java 刽子手游戏 https github com leleah EvilHangman blob master EvilHangman java https github com leleah EvilHangman b
  • 如何将文件透明地传输到浏览器?

    受控环境 IE8 IIS 7 ColdFusion 当从 IE 发出指向媒体文件 例如 mp3 mpeg 等 的 GET 请求时 浏览器将启动关联的应用程序 Window Media Player 我猜测 IIS 提供文件的方式允许应用程序
  • 从 android 简单上传到 S3

    我在网上搜索了从 android 上传简单文件到 s3 的方法 但找不到任何有效的方法 我认为这是因为缺乏具体步骤 1 https mobile awsblog com post Tx1V588RKX5XPQB TransferManage
  • 将 Long 转换为 DateTime 从 C# 日期到 Java 日期

    我一直尝试用Java读取二进制文件 而二进制文件是用C 编写的 其中一些数据包含日期时间数据 当 DateTime 数据写入文件 以二进制形式 时 它使用DateTime ToBinary on C 为了读取 DateTime 数据 它将首
  • org.jdesktop.application 包不存在

    几天以来我一直在构建一个 Java 桌面应用程序 一切都很顺利 但是今天 当我打开Netbeans并编译文件时 出现以下编译错误 Compiling 9 source files to C Documents and Settings Ad
  • Java中未绑定通配符泛型的用途和要点是什么?

    我不明白未绑定通配符泛型有什么用 具有上限的绑定通配符泛型 stuff for Object item stuff System out println item Since PrintStream println 可以处理所有引用类型 通
  • 应用程序关闭时的倒计时问题

    我制作了一个 CountDownTimer 代码 我希望 CountDownTimer 在完成时重新启动 即使应用程序已关闭 但它仅在应用程序正在运行或重新启动应用程序时重新启动 因此 如果我在倒计时为 00 10 分钟 秒 时关闭应用程序
  • 使用 SAX 进行 XML 解析 |如何处理特殊字符?

    我们有一个 JAVA 应用程序 可以从 SAP 系统中提取数据 解析数据并呈现给用户 使用 SAP JCo 连接器提取数据 最近我们抛出了一个异常 org xml sax SAXParseException 字符引用 是无效的 XML 字符
  • Keycloak - 自定义 SPI 未出现在列表中

    我为我的 keycloak 服务器制作了一个自定义 SPI 现在我必须在管理控制台上配置它 我将 SPI 添加为模块 并手动安装 因此我将其放在 module package name main 中 并包含 module xml 我还将其放
  • java迭代器内部是如何工作的? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我有一个员工列表 List
  • 中断连接套接字

    我有一个 GUI 其中包含要连接的服务器列表 如果用户单击服务器 则会连接到该服务器 如果用户单击第二个服务器 它将断开第一个服务器的连接并连接到第二个服务器 每个新连接都在一个新线程中运行 以便程序可以执行其他任务 但是 如果用户在第一个
  • Swagger/Openapi-Annotations:如何使用 $ref 生成 allOf?

    我正在生成 Rest 端点 包括添加OpenAPI Swagger对生成的代码进行注释 虽然它对于基本类型运行得很好 但我在自定义类方面遇到了一些问题 现在我有很多自定义类的重复架构条目 使用 Schema 实现 MyClass class

随机推荐

  • 八款国产操作系统

    点击上方蓝字 快速关注 目前世界上存在的那些操作系统 Windows MAC OS X MVX DOS VSE UNIX Linux等 很少见到国产操作系统的影子 你知道国产操作系统有那些吗 虽然国内的操作系统我们可能用不上 但我们有足够的
  • sd卡详细资料

    1 简介 SD卡是基于flash的存储卡 SD卡和MMC卡的区别在于初始化过程不同 SD卡的通信协议包括SD总线和SPI两类 SD卡使用卡内智能控制模块进行FLASH操作控制 包括协议 安全算法 数据存取 ECC算法 缺陷处理和分析 电源管
  • Nginx hls流媒体服务器实现直播

    通过Nginx模块nginx rtmp module实现hls流媒体服务器并用OBS进行推流 一 直播协议简介 首先 在搭建服务之前先了解下目前主流的几个直播协议 1 RTMP 实时消息传输协议 Real Time Messaging Pr
  • ERROR:root:Internal Python error in the inspect module.

    Google Colab运行终端命令报错 python xxxxx ERROR root Internal Python error in the inspect module Below is the traceback from thi
  • 维修汽车服务器,修车别被坑,老司机2分钟告诉你,修理厂和4S店之间不为人知的秘密!...

    在修车行业的新闻太多了 也有报道过一辆车坏了一颗螺丝修了几千上万块的新闻并不少见 对于修车多数人的第一反应就是 修车行业太坑了 尤其是私人修理厂 品牌修理店和4S店还稍微好点 但是事实真的是这样吗 首先让我们先了解一下现在的修理行业 现在开
  • 空间战场态势感知系统

    兵工科技 杂志就数字冰雹的 空间战场态势感知指挥可视化系统 对市场总监丁冬先生进行了专访报道 现代战争强调C4ISR技术 指挥中心在千里万里之外 要通过信息化技术对整个海 陆 空 天 电磁战场进行全面的了解 掌握和指挥控制 那么传统指挥部里
  • css在高度为百分比时候的文字垂直居中方法

    对于高度单位是px的div 想让文字垂直居中很简单 line height height就可以了 但是对于高度为百分比的div 如何让文字垂直居中呢 方法一 给需要垂直居中的文字增加一个父元素 给父元素设置 display table 给需
  • Unity3D 万向锁问题

    Unity3D 万向锁问题 1 问题 描述 在 unity3D中 对欧拉角的旋转顺序为Y X Z 那么我们可以通过一个Cube来直观看到这种现象 创建一个Cube 我们只要按照 Y X Z顺序 操作Cubu的Transform属性面板的欧拉
  • 启动gazebo时,[Err] [REST.cc:205] Error in REST request

    启动gazebo时 Err REST cc 205 Error in REST request 1 gazebo在安装ROS的时候就已经安装了 使用以下命令可检查是否安装成功 roslaunch gazebo ros empty world
  • 伸缩自如的ElasticSearch——文档CRUD操作

    文章目录 文档 文档元数据 index type id 取文档 更新文档 创建文档 删除文档 处理冲突 文档 在大多数应用中 多数实体或对象可以被序列化为包含键值对的 JSON 对象 一个 键 可以是一个字段或字段的名称 一个 值 可以是一
  • 移动端测试知识归纳版

    移动端测试 传统手机测试 移动端设备测试 是指测试手机本身 如抗压 抗摔 抗疲劳 抗低温高温等 也包括手机本身的功能 性能等测试 手机应用软件测试 移动端软件测试 手机应用软件是基于手机操作系统之上开发出来的软件 做这样的测试 就称为手机应
  • 如何解决win10 下的Linux子系统WSL忘记用户密码{官网解决方案}

    在使用WSL时 经常需要输入你创建用户名时对应的密码 但是如果忘记了也不要着急 官网提供了解决方法 1 win R 输入cmd后回车确认 进入你得终端 2 在这里输入 wsl u root 后回车 进入你的根目录 可以复制后在终端点击鼠标右
  • spacemacs操作卡顿的解决方法

    打开命令监控寻找卡顿来源 通过minor mode寻找卡顿来源 如何删除插件 删除emacs lisp 终极大法 spacemacs因为功能丰富 对工程操作带来了极大方便 但是因为插件的原因 偶尔会出现卡顿问题 打开命令监控 寻找卡顿来源
  • 四十三、视图层

    视图层 一 视图函数的返回值 二 视图函数返回json格式数据 三 form表单携带文件数据 四 FBV和CBV 4 1 FBV 4 2 CBV 4 3 CBV源码分析 一 视图函数的返回值 urls py path index views
  • 试画出下面系统的乃式图(nyquist图)【Matlab】

    试画出下面系统的乃式图 题目 G s 1 s 2
  • Linux:磁盘资源耗尽故障

    有两种经典原因 磁盘空间已被大量的数据占满 空间耗尽 解决办法 将没有用的大型文件转移或删除 文件i节点耗尽故障 文件过多 解决办法 删除 磁盘被大型文件占满 模拟 准备了一个2G大小的分区 然后进行挂载 我这是挂载到 mnt 然后df h
  • Flutter项目打包成安卓apk详解来了(解决安装没网络问题)

    Flutter项目打包成安卓apk步骤 cmd使用keytool创建 keystore 创建一个名为key properties的文件 编辑 android app build gradle文件配置签名 替换android app src
  • 《工程电磁场(第三版)》(倪光正 主编)复习

    看着 工程电磁场 本科期末考试试卷 A卷 看到填空题 每空2分 共30分 于是乎 开始了的 补考 复习计划 还是先从第一章开始去复习 了解什么是电磁场的数学物理基础 还有模型的构成以及需要了解到的麦克斯韦方程组 首先 了解电荷的分布形式 点
  • 大厂面试官常问的React和Vue难题,都在这儿了!

    作为国内应用最广的两个框架 Vue 和 React 是前端必须掌握的内容 也是面试的重点 但大多数读者都只擅长其中一个框架 当面试涉及到另一个框架的内容时 就答不好了 比如虚拟dom 两个框架中都有应用 面试官可能会笼统地问一句 如何理解虚
  • 栈(也被称作堆栈,一种遵循先进后出原则的数据结构)

    目录 1 栈 Stack 1 1 入栈 push 1 2 出栈 pop 1 3 栈的抽象数据类型 栈ADT 1 4 栈接口 2 利用数组实现栈 2 1 栈的实现 2 2 利用数组实现栈的优势与缺点 3 利用单链表实现栈 3 1 栈的实现 3