【05】栈:如何实现浏览器的前进和后退功能?

本文深入探讨了栈这一数据结构的定义、实现方式及其在函数调用、表达式求值、括号匹配和浏览器导航等功能中的应用。通过数组和链表两种实现方式,介绍了栈的动态扩容机制和时间复杂度分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 什么是栈?

  1. 典型的“栈”结构:后进者先出,先进者后出。
  2. 从栈的操作特性来看,是一种“操作受限”的线性表,只允许在一端插入和删除数据,只支持入栈 push()和出栈 pop()操作。

2. 为什么需要栈?

  1. 栈是一种操作受限的数据结构,其操作特性用数组和链表均可实现。
  2. 特定的数据结构是对特定场景的抽象,而且,数组或链表暴露了太多的操作接口,操作上的确灵活自由,但使用时就比较不可控,自然也就更容易出错。
  3. 所以,当某个数据集合只涉及在某端插入和删除数据,且满足后进者先出,先进者后出的操作特性时,我们应该首选栈这种数据结构。

3. 如何实现栈?

  1. 栈既可以用数组来实现,也可以用链表来实现。用数组实现的栈,叫作顺序栈,用链表实现的栈,叫作链式栈。
  2. 不管基于数组还是链表,入栈、出栈的时间复杂度都为 O(1)。
    不管是顺序栈还是链式栈,存储数据只需要一个大小为 n 的数组就够了。
    在入栈和出栈过程中,只需要一两个临时变量存储空间,所以空间复杂度是 O(1)。
    入栈、出栈只涉及栈顶个别数据的操作,所以时间复杂度都是 O(1)。
  3. 栈的API
public class Stack<Item> {
   
   
//压栈
public void push(Item item){
   
   }
//弹栈
public Item pop(){
   
   }
//是否为空
public boolean isEmpty(){
   
   }
//栈中数据的数量
public int size(){
   
   }
//返回栈中最近添加的元素而不删除它
public Item peek(){
   
   }
}
  1. 支持动态扩容的顺序栈(数组实现)
    思路:如果要实现一个支持动态扩容的栈,我们只需要底层依赖一个支持动态扩容的数组就可以了。当栈满了之后,我们就申请一个更大的数组,将原来的数据搬移到新数组中。
    出栈的时间复杂度是 O(1)。
    入栈操作,最好情况时间复杂度是 O(1),最坏情况时间复杂度是 O(n)。均摊时间复杂度为O(1)。
    时间复杂度分析:根据均摊复杂度的定义,可以得数组实现(自动扩容)符合大多数情况是O(1)级别复杂度,个别情况是O(n)级别复杂度,比如自动扩容时,会进行完整数据的拷贝。一般来说,均摊复杂度等于最好情况复杂度
    空间复杂度分析:在入栈和出栈的过程中,只需要一两个临时变量存储空间,所以O(1)级别。我们说空间复杂度的时候,是指除了原本的数据存储空间外,算法运行还需要额外的存储空间。
    实现代码:
public class StackOfArray<Item> implements Iterable<Item>{
   
   
//存储数据的数组
Item[] a = (Item[])new Object[1];
//记录元素个数N
int N = 0;
//构造器
public StackOfArray
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值