当前位置: 首页 > article >正文

数据结构(Java)—— 栈(Stack)

1. 概念

   栈 :一种特殊的线性表,其 只允许在固定的一端进行插入和删除元素操作 。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO Last In First Out )的原则。
  压栈:栈的插入操作叫做进栈 / 压栈 / 入栈, 入数据在栈顶
  出栈:栈的删除操作叫做出栈。 出数据在栈顶
如图所示:

2. 方法

2.1 栈的实例化

方法描述
new Stack<E>()基于数组实现的
new LinkedList<E>()基于链表实现的
new Deque<E>()基于双向队列实现的

代码示例:

 public static void main(String[] args) {
        Stack<Integer> stack1 = new Stack<>();
        LinkedList<Integer> stack2 = new LinkedList<>();
        Deque<Integer> stack3 = new LinkedList<>();
        stack1.push(1);
        stack1.push(2);
        stack1.push(3);
        stack2.push(10);
        stack2.push(20);
        stack2.push(30);
        stack3.push(11);
        stack3.push(22);
        stack3.push(33);
        System.out.println("======基于数组实现的栈======");
        System.out.println(stack1.peek());
        System.out.println(stack1.pop());
        System.out.println(stack1.peek());
        System.out.println("======基于链表实现的栈======");
        System.out.println(stack2.peek());
        System.out.println(stack2.pop());
        System.out.println(stack2.peek());
        System.out.println("======基于双向队列实现的栈======");
        System.out.println(stack3.peek());
        System.out.println(stack3.pop());
        System.out.println(stack3.peek());
    }

运行结果如下:

2.2 栈的使用

栈的一些主要操作方法如下:

方法
功能
E push(E e)
e入栈,并返回e
E pop()
将栈顶元素出栈并返回
E peek()
获取栈顶元素
int size()
获取栈中有效元素个数
boolean empty()
检测栈是否为空

代码示例:

public static void main(String[] args) {
    Stack<Integer> s = new Stack();
    s.push(1);
    s.push(2);
    s.push(3);
    s.push(4);
    System.out.println("size: "+s.size()); // 获取栈中有效元素个数---> 4
    System.out.println(s.peek()); // 获取栈顶元素---> 4
    s.pop(); // 4出栈,栈中剩余1 2 3,栈顶元素为3
    System.out.println(s.pop()); // 3出栈,栈中剩余1 2 栈顶元素为3
    if(s.empty()){
        System.out.println("栈空");
    }else{
        System.out.println("size: "+s.size());
    }
}

运行结果如下:

3. 栈的模拟实现

本文主要讲基于数组实现栈的功能

代码如下:

public class MyStack<E> {
    public Object[] elem;
    public int usedSize;

    public MyStack() {
        this.elem = new Object[10];
    }

    public void push(E val) {
        if(isFull()) {
            //扩容
            elem = Arrays.copyOf(elem,2*elem.length);
        }
        elem[usedSize] = val;
        usedSize++;
    }

    public boolean isFull() {
        return usedSize == elem.length;
    }

    public E pop() {
        if(empty()) {
            return null;
        }
        E oldVal = (E)elem[usedSize-1];
        usedSize--;
        return oldVal;
    }

    public E peek() {
        if(empty()) {
            return null;
        }
        return (E)elem[usedSize-1];
    }

    public boolean empty() {
        return usedSize == 0;
    }
    public int size(){
        return usedSize;
    }
}

注意:

1. 要使用一个变量(usedSize)记录数组(elem)中的有效元素个数;

2. 当数组满了(usedSize == elem.length )时,要对数组进行扩容;

3.进行出栈(pop)或者查看栈顶元素(peek)时,应先判断数组是否为空(empty)

代码使用:

public static void main(String[] args) {
    MyStack<Integer> s = new MyStack<>();
    s.push(1);
    s.push(2);
    s.push(3);
    s.push(4);
    System.out.println("size: "+s.size()); // 获取栈中有效元素个数---> 4
    System.out.println(s.peek()); // 获取栈顶元素---> 4
    s.pop(); // 4出栈,栈中剩余1 2 3,栈顶元素为3
    System.out.println(s.pop()); // 3出栈,栈中剩余1 2 栈顶元素为3
    if(s.empty()){
        System.out.println("栈空");
    }else{
        System.out.println("size: "+s.size());
    }
}

运行结果如下:

4. 应用场景 

  1. 函数调用:当程序调用一个函数时,会将返回地址、局部变量等信息压入栈中,等到函数执行完毕后,再从栈顶弹出这些信息。

  2. 表达式求值:在计算过程中,括号匹配、递归算法等都利用了栈来存储中间结果,如前缀表达式的求值。

  3. 浏览器历史记录:浏览网页时,每次前进或后退都是通过栈来管理历史状态的,后访问的页面会被推到栈顶,最先访问的则位于栈底。

  4. 深度优先搜索(DFS):在图或树的遍历中,栈常用于保存待访问的节点,遵循“先进先出”的规则。

  5. 括号匹配:检查字符串中的括号是否配对,可以使用两个栈,一个存放左括号,另一个存放遇到的右括号,通过比较左右括号是否一一对应来判断匹配。

  6. 系统调用堆栈:操作系统中,每个进程都有一个调用堆栈,用于跟踪函数调用的上下文。


http://www.kler.cn/a/463124.html

相关文章:

  • node内置模块之---path 模块
  • seata分布式事务详解(AT)
  • 非docker方式部署openwebui过程记录
  • 昆仑万维大数据面试题及参考答案
  • tcpdump指南(1)
  • 如何利用 ClickHouse 实现高级分析:MySQL 到 ClickHouse 实时数据同步指南
  • OpenCV的TickMeter计时类
  • 【Rust自学】8.3. String类型 Pt.1:字符串的创建、更新与拼接
  • Sentinel 介绍与使用指南:构建高可用、可靠的微服务架构
  • 大数据面试笔试宝典之大数据运维面试
  • 【文献精读笔记】Explainability for Large Language Models: A Survey (大语言模型的可解释性综述)(二)
  • 【Spring】Spring DI(依赖注入)详解—集合类型的注入——List、Set、Map的配置与注入
  • linux tar 文件解压压缩
  • 【人工智能】Python实现时序数据预测:ARIMA与LSTM的对比
  • Quartus DMA IP示例使用说明--MM接口
  • Spring实现输出带动态标签的日志
  • 【非关系型数据库Redis 】 入门
  • 32单片机从入门到精通之开发环境——库文件(六)
  • 三层交换机的原理详解
  • Keil中的gcc
  • 用PicGo向Github图床上传图片,然后通过markdown语言显示图片
  • Qt天气预报系统设计界面布局第四部分左边
  • 基于单片机中药存放环境监测系统的实现
  • 第三讲 比特币的早期发展
  • overscroll-behavior-解决H5在ios上过度滚动的默认行为
  • 茶叶连锁店管理系统(源码+文档+部署+讲解)