当前位置:   article > 正文

什么是栈/Java中的栈(栈定义/栈的时间复杂度/实现一个栈/栈的动态扩容)含示例代码

什么是栈/Java中的栈(栈定义/栈的时间复杂度/实现一个栈/栈的动态扩容)含示例代码

入门

如何理解“栈”

  • 他是一种受限的线性表
  • 分为 顺序栈/链式栈
  • 是一种 后进先出 的数据结构

如何实现一个“栈”

  • 栈主要包含两个操作,出栈和入栈。
  • 可以使用 链表或数据 存储数据
  • 分类:顺序栈、链式栈

支持动态扩容的顺序栈

image.png

image.png

  • 顺序栈可以支持动态扩容
  • 当容量达到上限,进行一次数据迁移即可。
  • 复杂度分析
    • 最好时间复杂度:O(1)
      • 简单的 push 操作。
    • 最坏时间复杂度:O(n)
      • 涉及到数据迁移,需要将原有 栈 中的数据,迁移到一个新的 栈 中。
      • 平均时间复杂度(摊还分析法):O(1)
    • 只有在容量达到 capacity 的时候才会进行数据迁移,此次的时间复杂度为 O(n)。
      • 将此次的时间复杂度,均摊到之前的 N-1 次,则每次的操作都只是均摊 O(1)

 

栈在软件工程中的实际应用

  • 浏览器的前进后退功能
    • 使用两个栈,一个存放前进,一个存放后退
  • JVM 栈的实现
    • 每个方法的调用都会生成一个栈帧,变量会被 push 都栈帧

image.png

  • 实现简单的计算器
    • 一个操作数栈、一个操作符栈。
    • 如果待入栈操作符的优先级等于或小于栈顶优先级,则进行计算

image.png

  • 检测括号(大中小括号)是否匹配
    • 左括号入栈,右括号与栈顶括号对比,如果一直则出栈

 

思考

为什么函数调用要用“栈”来保存临时变量呢?用其他数据结构不行吗?

  • 从调用函数进入被调用函数,对于数据来说,变化的是什么呢?是作用域。
  • 所以根本上,只要能保证每进入一个新的函数,都是一个新的作用域就可以。而要实现这个,用栈就非常方便。
  • 在进入被调用函数的时候,分配一段栈空间给这个函数的变量,在函数结束的时候,将栈顶复位,正好回到调用函数的作用域内。

 

实现

顺序栈

  1. public class ArrayStack {
  2. private final String[] items;
  3. private final int capacity;
  4. private int index = 0;
  5. public ArrayStack(int capacity) {
  6. this.capacity = capacity;
  7. items = new String[capacity];
  8. }
  9. public boolean push(String item) {
  10. if (index == capacity) return false;
  11. items[index++] = item;
  12. return true;
  13. }
  14. public String pop() {
  15. if (index == 0) return null;
  16. return items[--index];
  17. }
  18. public static void main(String[] args) {
  19. ArrayStack stack = new ArrayStack(10);
  20. System.out.println("first pop:" + stack.pop());
  21. Assert.isTrue(stack.push("123"));
  22. Assert.equals("123", stack.pop());
  23. System.out.println(stack.pop());
  24. }
  25. }

链式栈

  1. public class LinkedStack {
  2. //头结点是哨兵节点,不需要额外处理 null
  3. private ListNode current = new ListNode(null);
  4. public boolean push(String item) {
  5. ListNode next = new ListNode(item);
  6. //1. 给 cur 的next 赋值
  7. this.current.next = next;
  8. //2. 给 next 的 prev 赋值
  9. next.prev = current;
  10. //3. 当前指针指向下一个
  11. current = next;
  12. return true;
  13. }
  14. public String pop() {
  15. if (this.current.prev == null) {
  16. return null;
  17. }
  18. String val = current.val;
  19. current = current.prev;
  20. return val;
  21. }
  22. public static void main(String[] args) {
  23. LinkedStack stack = new LinkedStack();
  24. System.out.println("first pop:" + stack.pop());
  25. Assert.isTrue(stack.push("123"));
  26. Assert.equals("123", stack.pop());
  27. System.out.println("end:" + stack.pop());
  28. System.out.println("end:" + stack.pop());
  29. }
  30. }
  31. class ListNode {
  32. String val;
  33. ListNode next;
  34. ListNode prev;
  35. ListNode(String x) {
  36. val = x;
  37. }
  38. }

LeetCode 拓展

 

20 155 232 844 224 682 496.

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小舞很执着/article/detail/900674
推荐阅读
相关标签
  

闽ICP备14008679号