【数据结构与算法】之栈详解

栈(Stack)是一种基本的线性数据结构,遵循后进先出、先进后出的原则。本文将更详细地介绍栈的概念、特点、Java 实现以及应用场景。

1. 栈概念概述

想象一摞叠放的盘子,你只能从最上面取盘子,放盘子也只能放在最上面。栈就像这样一摞盘子,它只有一个开口,称为栈顶 (Top)。另一端封闭,称为栈底 (Bottom)。元素的添加操作称为入栈 (Push),删除操作称为出栈 (Pop)

栈是一种抽象数据类型 (ADT),这意味着我们只关心它的操作和特性,而不关心具体的实现方式。栈的关键操作包括:

  • push(item): 将元素 item 添加到栈顶。

  • pop(): 移除并返回栈顶元素。

  • peek(): 返回栈顶元素,但不移除它。

  • isEmpty(): 检查栈是否为空。

  • size(): 返回栈中元素的数量 (部分实现可能不包含此方法)。

2. 栈的特点

  • 后进先出 (LIFO): 这是栈最核心的特点,最后入栈的元素总是最先出栈。

  • 操作受限: 只能在栈顶进行插入和删除操作,这限制了访问元素的灵活性,但也保证了操作的高效性 (时间复杂度为 O(1))。

  • 有序性: 栈维护了元素的插入顺序,虽然不像队列那样严格的 FIFO,但仍然保留了元素的相对顺序。

3. 栈的 Java 实现 

Java 中可以使用数组或链表实现栈。

3.1 基于数组的实现

public class ArrayStack<T> {
    private T[] data; // 存储栈元素的数组
    private int top; // 栈顶指针,指向栈顶元素的索引,-1 表示栈空
    private int capacity; // 栈的容量

    public ArrayStack(int capacity) {
        this.capacity = capacity;
        this.data = (T[]) new Object[capacity]; // 创建泛型数组
        this.top = -1; 
    }


    //判空
    public boolean isEmpty() {
        return top == -1;
    }

    
    //判满
    public boolean isFull() {
        return top == capacity - 1;
    }

    
    //入栈操作
    public void push(T item) {
        if (isFull()) {
            // 数组实现需要处理栈满的情况,可以抛出异常或进行扩容
            throw new RuntimeException("Stack is full"); 
            // 或者: resizeArray();  // 扩容操作 (此处未实现)
        }
        data[++top] = item; // 先将 top 指针加 1,再放入元素
    }


    //出栈操作
    public T pop() {
        if (isEmpty()) {
            throw new RuntimeException("Stack is empty");
        }
        T item = data[top]; // 获取栈顶元素
        data[top--] = null; //  为了避免对象游离,建议将出栈元素置为 null。先获取元素再将 top 指针减 1
        return item;
    }


    //返回栈顶元素
    public T peek() {
        if (isEmpty()) {
            throw new RuntimeException("Stack is empty");
        }
        return data[top];
    }


    //返回栈容量
    public int size() {
        return top + 1;
    }
}

3.2 基于链表的实现

public class LinkedListStack<T> {
    private Node<T> top; // 指向栈顶节点的指针

    private static class Node<T> { // 链表节点的内部类
        T data;
        Node<T> next;

        Node(T data) {
            this.data = data;
        }
    }

    public LinkedListStack() {
        this.top = null; // 初始化栈为空
    }

    public boolean isEmpty() {
        return top == null;
    }


    //入栈
    public void push(T item) {
        Node<T> newNode = new Node<>(item); // 创建新节点
        newNode.next = top; // 新节点指向原栈顶
        top = newNode; // 更新栈顶指针
    }


    //出战
    public T pop() {
        if (isEmpty()) {
            throw new RuntimeException("Stack is empty");
        }
        T data = top.data; // 获取栈顶元素
        top = top.next; // 更新栈顶指针
        return data;
    }


    //返回栈顶元素
    public T peek() {
        if (isEmpty()) {
            throw new RuntimeException("Stack is empty");
        }
        return top.data;
    }
}

4. 栈的基本操作图解

4.1 初始化栈

4.2 进栈

分别是:元素 a 进栈;元素 b、c 进栈

4.3 出栈

分别是:元素 c 出栈;b、a 出栈

4.4 获取栈顶元素

略,先判断栈是否空,不空直接返回 data[top] 即可。

5. 各个操作的时间复杂度

  • 入栈 (push): 数组实现: 均摊 O(1) (因为需要考虑扩容的情况,但大多数情况下是 O(1)),链表实现: O(1)

  • 出栈 (pop): O(1)

  • 查看栈顶元素 (peek): O(1)

6. 栈的局限性

  • 大小受限 (数组实现): 使用数组实现时,需要预先指定栈的大小。如果数据量超过预设大小,需要进行扩容,这会带来性能开销。链表实现则没有这个限制,可以动态增长。

  • 不灵活的访问方式: 只能访问栈顶元素,无法直接访问其他元素。如果需要访问其他元素,需要先将栈顶元素依次弹出。

7. 总结和应用场景 

栈是一种简单但强大的数据结构,其 LIFO 特性使其在许多场景下都非常有用,例如:

  • 函数调用栈: 程序执行函数时,会将函数的局部变量、参数、返回地址等信息存储在栈中。当函数执行完毕后,这些信息会从栈中弹出,程序回到调用函数的地方继续执行。递归函数的实现也依赖于函数调用栈。

  • 表达式求值: 例如,可以使用栈来计算后缀表达式 (逆波兰表达式)。

  • 浏览器历史记录: 浏览器的前进和后退按钮利用了栈的特性。点击后退按钮时,会从栈中弹出上一个访问的页面。

  • 撤销操作 (Undo/Redo): 许多软件的撤销操作使用了栈来存储操作的历史记录。每次执行操作时,将操作的信息压入栈中。点击撤销按钮时,从栈中弹出最近的操作并将其逆操作应用。

  • 深度优先搜索 (DFS): 图算法中常用的深度优先搜索算法使用栈来存储待访问的节点。

理解栈的概念和实现对于程序员来说至关重要,它能帮助我们更好地设计和优化程序。

希望这篇文章能帮助各位看官更好地理解栈这种重要的数据结构! 下期见,谢谢~

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

html和css实现页面

任务4 html文件 任务5 htm文件 css文件 任务6 html文件 css文件 任务7 html文件 css文件

工业交换机的电源类型

工业交换机的电源通常有以下几种类型和注意事项&#xff1a; 1. 电源类型&#xff1a; 交流电源&#xff08;AC&#xff09;&#xff1a;一些工业交换机使用标准的AC电源&#xff0c;通常是110V或220V。适用于有稳定电源环境的场合。 直流电源&#xff08;DC&#xff09;&#…

javaWeb项目-ssm+jsp大学生校园兼职系统功能介绍

本项目源码&#xff08;点击下方链接下载&#xff09;&#xff1a;java-ssmjsp大学生校园兼职系统实现源码(项目源码-说明文档)资源-CSDN文库 项目关键技术 开发工具&#xff1a;IDEA 、Eclipse 编程语言: Java 数据库: MySQL5.7 框架&#xff1a;ssm、Springboot 前端&#x…

使用Selenium时,如何模拟正常用户行为?

Selenium作为自动化测试和网页数据抓取的利器&#xff0c;被广泛应用于自动化网页交互、爬虫开发等领域。然而&#xff0c;随着网站反爬虫技术的不断升级&#xff0c;简单的自动化脚本很容易被识别和阻止。因此&#xff0c;模拟正常用户行为&#xff0c;降低被检测的风险&#…

springmvc+jdk1.8升级到springboot3+jdk17(实战)

1.查找springboot3官方要求 这里查的是springboot 3.2.6版本的 2.升级jdk到17 Java EE 8之后&#xff0c;Oracle在19年把javax捐给了eclipse基会&#xff0c;但不允许使用javax的命名空间&#xff0c;所以eclipse才发展成为现在的Jakarta ee标准。Springboot3后使用Jakarta a…

HTML简单版的体育新闻案例

代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta name"viewport" content"widthdevice-width, initial-scale1.0"> <title>Document</title> &l…

使用QT绘图控件QCustomPlot绘制波形图

使用QT绘图控件QCustomPlot绘制波形图 下载QCustomPlot 下载QCustomPlot,链接路径 解压之后就能看到源代码了 在Qt中添加QCustomPlot的帮助文档 在Qt Creator的菜单:工具–>选项–>帮助–>文档–>添加qcustomplot\documentation\qcustomplot.qch文件。

windbg调试exedump步骤,技巧总结

所有信息参考官方文档&#xff1a;开始使用 WinDbg&#xff08;用户模式&#xff09; - Windows drivers | Microsoft Learn 需要着重关注的标签页如下&#xff1a; 用户模式&#xff08;入门&#xff09; 命令摘要 Help 菜单上的命令 Contents.sympath&#xff08;设置符号…

解锁PDF权限密码

目录 背景: 定义与功能&#xff1a; 过程&#xff1a; 主要功能&#xff1a; 使用方式&#xff1a; 使用限制&#xff1a; 注意事项&#xff1a; 总结&#xff1a; 背景: 前段时间自己设置了PDF文件的许可口令&#xff0c;忘了口令导致自己无法编辑内容等&#xff0c;这…

OpenCV和HALCON

OpenCV和HALCON是两种广泛用于图像处理和计算机视觉的开发库&#xff0c;它们各有优缺点&#xff0c;适合不同的应用场景。以下是两者的比较&#xff1a; 1. 开发背景与定位 OpenCV (Open Source Computer Vision Library)&#xff1a; 开源库&#xff0c;最初由Intel开发&…

Matlab中计算道路曲率的几种方法

我使用Prescan采集到的道路中心线数据&#xff0c;都是离散点&#xff08;x&#xff0c;y&#xff0c;z&#xff09;&#xff0c;但在作研究时&#xff0c;通常都是道路曲率&#xff0c;这时需要将离散点坐标转换为曲率&#xff0c;但通过计算得到的曲率与实际曲率有一些误差&a…

sentinel原理源码分析系列(八)-熔断

限流为了防止过度使用资源造成系统不稳&#xff0c;熔断是为了识别出”坏”资源&#xff0c;避免好的资源受牵连(雪崩效应)&#xff0c;是保证系统稳定性的关键&#xff0c;也是资源有效使用的关键&#xff0c;sentinel熔断插槽名称Degrade(降级)&#xff0c;本人觉得应该改为熔…

怎么提取pdf的某一页?批量提取pdf的某一页的简单方法

怎么提取pdf的某一页&#xff1f;在日常工作与学习中&#xff0c;我们经常会遇到各式各样的PDF文件&#xff0c;它们以其良好的兼容性和稳定性&#xff0c;成为了信息传输和存储的首选格式。然而&#xff0c;在浩瀚的文档海洋中&#xff0c;有时某个PDF文件中的某一页内容尤为重…

一篇文章进阶MySQL数据库

一&#xff0c;MySQL数据库体系结构 层级说明连接层主要完成一些类似于连接处理&#xff0c;授权认证&#xff0c;及相关的安全方案。服务器也会为安全接入的每个客户端验证它所具有的操作权限服务层完成大多数的核心服务功能&#xff0c;如SQL接口&#xff0c;并完成缓存的查询…

使用 Pake 一键打包网页为桌面应用 / 客户端

项目 项目&#xff1a;https://github.com/tw93/Pake/ 免费ICO图片&#xff1a;https://icon-icons.com/zh/ 设置环境 以下教程仅针对windows系统适用 请确保您的 Node.js 版本为 18 或更高版本 文档&#xff1a;https://v1.tauri.app/zh-cn/v1/guides/getting-started/prerequ…

java小游戏实战-星空大战(接口、继承、多态等多种方法)

环境&#xff1a;Windows系统Eclipse/idea、jdk8 1.创建英雄类 2.创建飞机类 3.创建敌人接口 package com.plane;public interface Enemy { /* *得分的方法 */ public int getScore(); } 4.创建小蜜蜂类 5.创建奖励接口 package com.plane;public interface Award {public …

【Linux笔记】Linux命令与使用

博文将不断学习补充 学习参考博文&#xff1a; Linux命令大全&#xff1a;掌握常用命令&#xff0c;轻松使用Linux操作系统-CSDN博客 文件或目录操作命令 zip # zip是使用最多的文档压缩格式 # 方便跨平台使用&#xff0c;但是压缩率不是很高 zip指令未安装 安装zip yum ins…

深度学习相关知识点

文章目录 epoch/batch/batch_size的关系dense visual predictionlogits epoch/batch/batch_size的关系 Epoch&#xff1a;模型在整个数据集上完成一次训练。一个epoch后&#xff0c;模型已经看过所有的训练数据&#xff0c;执行了正向传播和反向传播。通常训练需要多个epoch&a…

【C#】搭建环境之CSharp+OpenCV

在我们使用C#编程中&#xff0c;对图片处理时会用到OpenCV库&#xff0c;以及其他视觉厂商提供的封装库&#xff0c;这里因为OpenCV是开源库&#xff0c;所以在VS资源里可以直接安装使用&#xff0c;这里简单说明一下搭建的步骤及实现效果&#xff0c;留存。 1. 项目创建 1.1…

055_基于python摄影平台交流系统

目录 系统展示 开发背景 代码实现 项目案例 获取源码 博主介绍&#xff1a;CodeMentor毕业设计领航者、全网关注者30W群落&#xff0c;InfoQ特邀专栏作家、技术博客领航者、InfoQ新星培育计划导师、Web开发领域杰出贡献者&#xff0c;博客领航之星、开发者头条/腾讯云/AW…