java中的栈

Java - 数据结构,栈 java虚拟机栈也是栈,就是JVM中的一块内存,也是符合栈的规则 – 先进后出规则方法区:存放类定义信息、字节码、常量等数据,在Sun HotSpot JVM中,这块也称为Perm Gen。堆:创建的对象信息将放入堆中,堆内部如何实现各虚拟机各不相同,对于Sun HotSpot JVM来说又分为Young Gen和Tenured Gen,更详细描述参见《[Java性能剖析]Sun JVM内存管理和垃圾回收 》 阅读详情

一、栈的理解

栈(Stack)是一种受限的线性数据结构,所谓受限是指栈只暴露栈顶和栈底的操作,其底层是由数组实现的。栈的特性是先进后出,类似于手枪压弹,原理示意图如下:
在这里插入图片描述

二、Stack的继承关系

在这里插入图片描述

三、被弃用的Stack

3.1 被弃用的原因

从继承关系中,我们可以看到Stack的基本方法与底层实现,由于Vector是动态数组接口,其底层的实现是数组,因此,Stack的底层实现也是数组,且继承了Vector的公共方法。
从前文(简析Vector类)我们知道,Vector类具有动态扩容和随机访问的特性,因此,继承了Vector类的Stack也同样具有这些特性,这恰好违背了Stack数据结构的设计原理,正因为如此,Java中的Stack一直被认为是糟糕的实现,官方也将Stack标志为“弃用”(deprecated)。
综上所述,导致Stack糟糕实现的原因是Stack与Vector类的关系出现了错误,不应该是继承关系(is-a),而应是组合关系(has-a)。

3.2 如何替代

官方推荐使用Deque接口来实现Stack:

Deque<E> stack = new ArrayDeque<>();

虽然官方做出了推荐,但是我们仍然可以发现,Deque实现的Stack实质是一个双端队列,可以在队列的两端实现插入和删除操作,仍然破坏力了封装性,并不安全,可以看出这并不是一个完美的方法。
因此,在实际中更推荐大家再做一层封装,通过逻辑限定为只能一端操作插入和删除,形成一个真正的栈。

3.3 队列实现栈

用队列实现栈,只需要⼀个队列作为底层数据结构。
要实现的栈的API如下:

class MyStack {
	/** 添加元素到栈顶 */
	public void push(int x);
	/** 删除栈顶的元素并返回 */
	public int pop();
	/** 返回栈顶元素 */
	public int top();
	/** 判断栈是否为空 */
	public boolean empty();
}

先说 push API,直接将元素加⼊队列,同时记录队尾元素,因为队尾元素相当于栈顶元素,如果要 top 查
看栈顶元素的话可以直接返回:

class MyStack {
	Queue<Integer> q = new LinkedList<>();
	int top_elem = 0;
	/** 添加元素到栈顶 */
	public void push(int x) {
		// x 是队列的队尾,是栈的栈顶
		q.offer(x);
		top_elem = x;
	}
	/** 返回栈顶元素 */
	public int top() {
		return top_elem;
	}
}

我们的底层数据结构是先进先出的队列,每次 pop 只能从队头取元素;但是栈是后进先出,也就是说 pop
API 要从队尾取元素:
在这里插入图片描述
解决⽅法简单粗暴,把队列前⾯的都取出来再加⼊队尾,让之前的队尾元素排到队头,这样就可以取出了:
在这里插入图片描述

/** 删除栈顶的元素并返回 */
public int pop() {
	int size = q.size();
	while (size > 1) {
		size--;
	}
	// 之前的队尾元素已经到了队头
	return q.poll();
}

这样实现还有⼀点⼩问题就是,原来的队尾元素被提到队头并删除了,但是 top_elem 变量没有更新,我们
还需要⼀点⼩修改:

/** 删除栈顶的元素并返回 */
public int pop() {
	int size = q.size();
	// 留下队尾 2 个元素
	while (size > 2) {
		q.offer(q.poll());
		size--;
	}
	// 记录新的队尾元素
	top_elem = q.peek();
	q.offer(q.poll());
	// 删除之前的队尾元素
	return q.poll();
}

最后,API empty 就很容易实现了,只要看底层的队列是否为空即可:

/** 判断栈是否为空 */
public boolean empty() {
	return q.isEmpty();
}

很明显,⽤队列实现栈的话,pop 操作时间复杂度是 O(N),其他操作都是 O(1) 。

3.4 面试中的Stack

如果面试中关注的是算法和程序的逻辑,那么数据结构的使用就不是重点,但是如果能用Deque实现,那自然是更好,尤其是需要考察对Java原因的理解。

参考资料

[1] https://blog.youkuaiyun.com/Tommy_____/article/details/106445631
[2] labuladong算法秘籍V1.1

Java进阶面试合集笔记——19个技术栈(2024最新总结) 什么是ActiveMQ?ActiveMQ服务器宕机怎么办?丢消息怎么办?持久化消息非常慢怎么办?消息的不均匀消费怎么办?死信队列怎么办?ActiveMQ中的消息重发时间间隔和重发次数吗? 阅读详情

相关推荐

Java随笔-栈与栈帧

每一个方法的执行都对应着压栈和出栈

古典码 1360

深入理解Java中的栈(超详细)新手必看

栈(Stack)是一种常见的数据结构,具有后进先出(LIFO,Last In First Out)的特性,即最后入栈的元素最先出栈。栈通常用于存储临时性的数据,如方法调用过程中的局部变量、操作数栈等。在计算机科学中,栈的应用非常广泛,包括编程语言中的函数调用、内存分配以及表达式求值等领域。在Java编程语言中,栈也被广泛应用于方法调用和内存管理的过程中。双端栈(Double Ended Stack),也被称为双端队列(Deque),是一种支持在两端进行插入和删除操作的数据结构。

2201_75437633的博客 2万+

CUPED (Controlled-experiment using Pre-Experiment Data) 论文学习笔记

CUPED是一种用于提升A/B测试灵敏度的方差缩减技术。它通过利用实验前用户行为数据(协变量X)构建调整后的指标Y_cuped=Y-θ(X-E[X]),其中θ=Cov(Y,X)/Var(X)。这种方法能在保持处理效应估计无偏的前提下,将方差降低1-ρ²倍(ρ为前后指标相关性)。CUPED的核心优势在于:不改变平均处理效应的估计,但能显著提升统计功效,使得实验更容易检测到微小但真实的效应,同时减少所需样本量或实验周期。该技术特别适用于用户异质性大、指标方差高的场景。

pursuit的博客 2143

Java数据结构-栈

栈

Vampire的博客 5641

Ubuntu20.04安全重启后WiFi图标消失?MT7922网卡驱动修复全攻略

本文详细解析了Ubuntu20.04安全重启后WiFi图标消失的问题,特别是针对MT7922网卡驱动失效的情况。通过诊断命令和分步解决方案,包括禁用PCIe ASPM、更新无线固件和升级HWE内核,帮助用户快速恢复网络连接。文章还提供了进阶排查技巧和系统优化建议,确保WiFi稳定运行。

weixin_29202687的博客 368

别让你的URDF模型在Gazebo里‘躺平’:手把手教你配置libgazebo_ros_diff_drive插件让两轮小车动起来

本文详细解析了如何在Gazebo中配置libgazebo_ros_diff_drive插件,使两轮小车模型实现动态仿真。从URDF模型到传动装置,再到差速驱动插件的精细调参,手把手教你解决机器人‘躺平’问题,提升ROS1与Gazebo仿真的实战能力。

weixin_42552716的博客 333

Java数据结构01——栈

java java数据结构 栈

qq_64037280的博客 4385

Mathtype公式下标深度调整技巧:解决固定行距下的显示不全问题

本文针对在Word等文档中设置固定行距时,Mathtype公式下标显示不全的问题,提供了专业解决方案。核心在于调整Mathtype软件内部的“下标深度”参数,通过修改单个公式或批量格式化全文,使公式完美适配固定行距,确保下标清晰完整,且不影响文档整体排版。

pepsi的博客 1497

day-2-3-4

java初识栈

haodi12138的博客 477

电子电气架构 --- 整车电源管理

保证启动能力:防止因电池电量耗尽而导致的车辆无法启动,这对于确保车辆在任何时候都能可靠运行至关重要。 延长电池寿命:通过避免电池深度放电,有助于延长其使用寿命,减少更换电池的需求和成本。 提升用户体验:虽然负载被关闭可能会暂时影响舒适度,但通过在必要时自动采取行动,可以减少驾驶员的焦虑和不确定性,提高整体的用户满意度。

Soly_kun的博客 1083

【AI编程】Claude Code 最强AI 编程利器项目实战详解

Claude Code 最强AI 编程利器项目实战详解

congge 7392

Java中的栈

栈是一种遵循后进先出(LIFO,Last In First Out)原则的数据结构。在栈中,最后进入的元素会最先被移除。这种特性使得栈在许多算法和程序设计中非常有用,例如在处理函数调用、表达式求值和内存管理等方面。在Java中,除了使用内置的Stack类,我们可以通过不同的数据结构来实现栈。栈作为一种基本的数据结构,在Java编程中扮演着重要的角色。无论是内置的Stack类,还是自定义的栈实现,都能帮助我们解决各种编程问题。理解栈的原理和应用,对于提高编程能力和解决复杂问题具有重要意义。版权声明。

ning的博客 925

eNSP中玩转Python自动化——解锁网工新姿势(一)

Python自动化一、安装Paramiko模块二、搭建实验环境1、桥接电脑网卡2、配置交换机IP地址交换机配置测试ensp的交换机与电脑的连通性:交换机配置SSHXshell验证三、Python脚本1、执行python脚本2、同步成功 一、安装Paramiko模块 首先安装Python3 然后安装pip解释器 最后安装Paramiko模块 Windows+R打开Cmd,输入命令: pip3 install paramiko 进入python,导入 paramiko模块: import paramiko

LiBai'S BLOG 2万+

栈的Java实现--链栈

栈的Java实现--链栈   链栈的基本结构: 链栈的入栈操作:  让top引用指向新的节点,新节点的next指向原来的top 记录栈内元素个数的size+1 链栈的出栈操作:  top引用指向原栈顶元素的下一个元素(top.next),并

生命在于折腾 4057

【Py/Java/C++/C/JS/Go六种语言OD独家2024E卷真题】20天拿下华为OD笔试之【固定滑窗】2024E-考勤信息【欧弟算法】全网注释最详细分类最全的华为OD真题题解

可上练习华子OD、大厂真题绿色聊天软件戳oj1441了解算法冲刺训练(备注【优快云】否则不通过)

weixin_48157259的博客 617

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

java压栈和弹栈

好好学习,天天向下 一、栈的存放 局部变量 堆中对象的引用(对象在堆内存中的 地址) 全局变量存储在堆中 局部变量存储在栈中 栈的属性:每条线程都有一个独立的栈,在线程创建时创建 二、栈的操作 栈的存取顺序是先进后出,后进先出,就像是桶装羽毛球,先放进去的后拿出来 public class storage { //先规定栈的最大容量 Object[] objs; //获...

King的博客 4589

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Java 栈

栈是一种特殊的线性表,它仅允许在表的一端(栈顶,Top)进行插入操作(入栈,push)和删除操作(出栈,pop),而在表的另一端(栈底,Bottom)不允许任何操作。这种 “后进先出” 的特性,使其与队列(FIFO)形成鲜明对比。形象地说,栈就像一摞叠放的盘子:只能从最上面添加盘子(入栈),也只能从最上面拿走盘子(出栈),最下面的盘子往往是最早放入却最后取出的。

Gu_yyqx的博客 835

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

Java栈和栈桢

Java中的栈 每当启用一个线程时,JVM就为他分配一个Java栈,栈是以帧为单位保存当前线程的运行状态。某个线程正在执行的方法称为当前方法,当前方法使用的栈帧称为当前帧,当前方法所属的类称为当前类,当前类的常量池称为当前常量池。当线程执行一个方法时,它会跟踪当前常量池。 每当线程调用一个Java方法时,JVM就会在该线程对应的栈中压入一个帧,这个帧自然就成了当前帧。当执行这个方法时,

魔力鸟的专栏 4692

java让对象分配在栈上_Java中的栈上分配

什么是栈上分配栈上分配是java虚拟机提供的一种优化技术,基本思想是对于那些线程私有的对象(指的是不可能被其他线程访问的对象),可以将它们打散分配在栈上,而不是分配在堆上。分配在栈上的好处是可以在函数调用结束后自行销毁,而不需要垃圾回收器的介入,从而提供系统的性能。栈上分配的一个技术基础是进行逃逸分析。逃逸分析的目的是判断对象的作用域是否有可能逃逸出函数体。下面的代码显示了一个逃逸的对象:publ...

weixin_33561910的博客 3531

【栈和队列】java实现栈和队列以及集合中的栈和队列

【栈和队列】java实现栈和队列,让大家更加深刻的认识栈和队列

程序员良辰 1052

java栈的实现

一.数组实现的栈,能存储任意类型的数据。 /** * java 使用数组来实现栈,能存储任意数据 * * @author Linging * @date 2019/2/10 * */ import java.lang.reflect.Array; public class ArrayStack&amp;lt;T&amp;gt; { private final static int DEFA...

Linging_24的博客 2507

Java中的栈和队列

栈和队列是构建更复杂数据结构的基础,如二叉树、图、堆等。它们在不同的算法和系统设计中扮演着关键角色。理解它们的工作原理和应用场景对于任何希望深入学习计算机科学的人来说都是必不可少的。通过掌握这些基本概念,我们可以更好地理解和设计复杂的系统,从而解决实际问题。

2301_78804510的博客 1234

Java获取栈顶元素 不出栈

一:概述在Java编程中,栈(Stack)是一种常见的数据结构,它遵循后进先出(LIFO)的原则。在实际开发中,我们经常需要获取栈顶元素而不移除它,这样的操作可以让我们保持栈的状态不变,同时获取所需的信息。本文将介绍几种在Java中获取栈顶元素而不出栈的方法,并提供实际的案例。二:具体方法<1>使用peek()...

cnzzs的博客 1181

java中堆 栈的英文_Java中的栈和堆

人们常说堆栈堆栈,堆和栈是内存中两处不一样的地方,什么样的数据存在栈,又是什么样的数据存在堆中?这里浅谈Java中的栈和堆首先,将结论写在前面,后面再用例子加以验证。Java的栈中存储以下类型数据,栈对应的英文单词是Stack基本类型引用类型变量方法栈的优势是,存取速度比堆要快,仅次于寄存器,栈数据可以共享。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。栈中主要存放一些基本类型的变...

weixin_33147807的博客 2554

java栈深度

什么是java栈深度? java栈深度有什么用? 我们知道java栈是java虚拟机的一个重要的组成部分,在栈里进行线程操作,存放方法参数等等。 栈在初始化过后是有一定的大小的。 public class Test{          private int count = 0;          public void testAdd(){         count ++;

qq_28385797的博客 1万+
上一篇: 简述Vector
下一篇: 简析时间复杂度与空间复杂度
Archie敲键盘
博客等级 码龄7年 9粉丝 25原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值