当你依次访问完一串a-b-c页面之后,点击浏览器的后退按钮,就可以查看之前浏览的页面a和b。当你后退到页面a,点击前进按钮,就可以重新查看页面b和c。但是,如果你后退到页面b后,点击了新的页面d,就无法再通过前进后退功能查看页面c了。

要实现上述功能,就需要用到“栈”这个数据结构。

一. 简介

“栈”是一种有特定规则的数据结构,当某个数据集合只设计在一端进行插入和删除数据的操作,并且满足后进先出,先进后出的特性,我们就应该首选“栈”这种数据结构。

从功能上来说,数组或链表可以替代栈,但是,特定的数据结构是对特定场景的抽象,而且,数据或链表暴露了太多操作接口,操作上的确是灵活自由,但这也导致在使用时就比较不可控,也就更加容易出错。

二. 栈的实现

栈包含两个操作-----出栈和入栈
栈包含两种实现------用数组实现的顺序栈和用链表实现的链式栈

// 基于数组实现的顺序栈
public class ArrayStack {
  private String[] items;  // 数组
  private int count;       // 栈中元素个数
  private int n;           // 栈的大小

  // 初始化数组,申请一个大小为 n 的数组空间
  public ArrayStack(int n) {
    this.items = new String[n];
    this.n = n;
    this.count = 0;
  }

  // 入栈操作
  public boolean push(String item) {
    // 数组空间不够了,直接返回 false,入栈失败。
    if (count == n) return false;
    // 将 item 放到下标为 count 的位置,并且 count 加一
    items[count] = item;
    ++count;
    return true;
  }
  
  // 出栈操作
  public String pop() {
    // 栈为空,则直接返回 null
    if (count == 0) return null;
    // 返回下标为 count-1 的数组元素,并且栈中元素个数 count 减一
    String tmp = items[count-1];
    --count;
    return tmp;
  }
}

栈的时间空间复杂度均为O(1)

支持动态扩容的顺序栈时间复杂度:
数据结构与算法之栈

三. 栈的实践应用

  1. 程序运行时的栈帧
  2. 表达式求值
  3. 括号匹配

解答开篇:
在开篇的浏览器应用中,我们使用两个栈X和Y。
顺序查看时:
数据结构与算法之栈
后退时:
数据结构与算法之栈
开启新网页时:
数据结构与算法之栈

相关文章: