数据结构与算法之栈

当你依次访问完一串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。
顺序查看时:
在这里插入图片描述
后退时:
在这里插入图片描述
开启新网页时:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
(Stack)是一种常见的数据结构,它是一种只允许在一端进行插入和删除操作的线性表,这一端被称为顶。的特点是后进先出(Last-In-First-Out,简称 LIFO),即最后压入的元素最先弹出。 在 Java 中,可以使用数组或链表来实现。下面分别介绍数组和链表实现的方法。 1. 数组实现 数组实现时,需要定义一个数组和一个指针 top,top 指向顶。中的元素从数组的末尾开始存储,每当有一个元素入时,top 指针加 1;每当有一个元素出时,top 指针减 1。 以下是一个基于数组实现的的示例代码: ```java public class ArrayStack { private int[] stack; // 数组 private int top; // 顶指针 public ArrayStack(int size) { stack = new int[size]; top = -1; // 初始化顶指针为 -1 } // 判断是否为空 public boolean isEmpty() { return top == -1; } // 判断是否已满 public boolean isFull() { return top == stack.length - 1; } // 入 public void push(int data) { if (isFull()) { System.out.println("已满,无法入。"); return; } stack[++top] = data; } // 出 public int pop() { if (isEmpty()) { System.out.println("为空,无法出。"); return -1; } return stack[top--]; } // 获取顶元素 public int peek() { if (isEmpty()) { System.out.println("为空,无法获取顶元素。"); return -1; } return stack[top]; } } ``` 2. 链表实现 链表实现时,需要定义一个链表头节点和一个指针 top,top 指向顶。每当有一个元素入时,该元素成为新的头节点,其 next 指针指向原来的头节点;每当有一个元素出时,头节点指针向下移动一个位置。 以下是一个基于链表实现的的示例代码: ```java public class LinkedStack { private Node top; // 顶指针 public LinkedStack() { top = null; // 初始化顶指针为 null } // 判断是否为空 public boolean isEmpty() { return top == null; } // 入 public void push(int data) { Node newNode = new Node(data); newNode.next = top; top = newNode; } // 出 public int pop() { if (isEmpty()) { System.out.println("为空,无法出。"); return -1; } int data = top.data; top = top.next; return data; } // 获取顶元素 public int peek() { if (isEmpty()) { System.out.println("为空,无法获取顶元素。"); return -1; } return top.data; } private class Node { private int data; private Node next; public Node(int data) { this.data = data; this.next = null; } } } ``` 以上是两种常见的的实现方法,它们在效率和空间占用上略有差别,具体实现应根据具体情况选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值