08 | 栈:如何实现浏览器的前进和后退功能?

后进者先出,先进者后出,这就是典型的“栈”结构。栈是一种“操作受限”的线性表,只允许在一端插入和删除数据。

为什么要使用到“栈”这种操作受限的数据结构?

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

当某个数据集合只涉及在一端插入和删除数据,并且满足后进先出、先进后出的特性,这时我们就应该首选“栈”这种数据结构

如何实现一个栈?

  • 栈既可以用数组来实现,也可以用链表来实现。
  • 用数组实现的栈,我们叫作顺序栈,
  • 用链表实现的栈,我们叫作链式栈

顺序栈的实现:

// 基于数组实现的顺序栈
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() {// 栈为空,则直接返回nullif (count == 0) return null;// 返回下标为count-1的数组元素,并且栈中元素个数count减一String tmp = items[count-1];--count;return tmp;}
}

栈操作的复杂度分析

存储数据只需要一个大小为 n 的数组就够了。在入栈和出栈过程中,只需要一两个临时变量存储空间,所以空间复杂度是 O(1);

入栈、出栈只涉及栈顶个别数据的操作,所以时间复杂度都是 O(1);

如何实现动态扩容的顺序栈?

动态扩容的数组:当数组空间不够时,我们就重新申请一块更大的内存,将原来数组中数据统统拷贝过去。这样就实现了一个支持动态扩容的数组;要实现一个支持动态扩容的栈,我们只需要底层依赖一个支持动态扩容的数组就可以了。当栈满了之后,我们就申请一个更大的数组,将原来的数据搬移到新数组中

栈的应用

函数调用

操作系统给每个线程分配了一块独立的内存空间,这块内存被组织成“栈”这种结构, 用来存储函数调用时的临时变量。每进入一个函数,就会将临时变量作为一个栈帧入栈,当被调用函数执行完成,返回之后,将这个函数对应的栈帧出栈;

代码示例:


int main() {int a = 1; int ret = 0;int res = 0;ret = add(3, 5);res = a + ret;printf("%d", res);reuturn 0;
}int add(int x, int y) {int sum = 0;sum = x + y;return sum;
}

编译器通过栈实现求值表达式的求值

四则运算法则:34+13*9+44-12/3

编译器就是通过两个栈来实现的。其中一个保存操作数的栈,另一个是保存运算符的栈。我们从左向右遍历表达式,当遇到数字,我们就直接压入操作数栈;当遇到运算符,就与运算符栈的栈顶元素进行比较;如果比运算符栈顶元素的优先级高,就将当前运算符压入栈;如果比运算符栈顶元素的优先级低或者相同,从运算符栈中取栈顶运算符,从操作数栈的栈顶取 2 个操作数,然后进行计算,再把计算完的结果压入操作数栈,继续比较;

如何实现浏览器的后退和前进功能?

  • 定义两个栈X和Y,将首次浏览的页面压入栈X,当点击后退按钮时,再依次从栈X中出栈,并将出栈的依次压入栈Y,当点击前进时,就从Y中取出数据放入X中;
  • 当X中没有数据时,表示页面不可后退,当Y中没有数据时表示页面不可前进;
  • 当跳转了新的页面,新的页面压入栈X中,同时需要清空栈Y,也即当前页面不可以前进了;

 

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/419141.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

09 | 队列:队列在线程池等有限资源池中的应用

队列定义 先进者先出,这就是典型的“队列”。队列跟栈一样,也是一种操作受限的线性表数据结构。 顺序队列和链式队列 顺序队列:用数组实现的队列// 用数组实现的队列 public class ArrayQueue {// 数组:items,数组大…

PICT实现组合测试用例

成功安装后,在命令行中输入命令pict: 可以看到pict命令的一些选项:/o:N 组合数,默认值为2,即pict生成的测试用例集中每条测试数据会有两个值与其他测试集是不同的;/d:C 值与值之间的分隔符,…

10 | 递归:如何用三行代码找到“最终推荐人”?

什么是递归? 递归是一种应用非常广泛的算法(或者编程技巧)。很多数据结构和算法的编码实现都要用到递归,比如 DFS 深度优先搜索、前中后序二叉树遍历等等。 去的过程叫“递”,回来的过程叫“归” 场景 周末你带着女…

前端学习(1723):前端系列javascript之uniapp语法下

<template><view><view v-if"show">uniapp</view><view>geyao</view><view v-for"item in items">{{item}}</view><view v-on:click"onClick(uni-app)">点击</view></view> …

瑞星杀毒软件、奇虎360杀毒软件、360卫士、百度卫士联手,搞不定弹出广告 amp; 恶意广告图标...

一位网友说他的电脑近期出了问题&#xff1a;开机后桌面和任务栏上的高速启动栏会出现恶意图标。删除了下次开机又会出现&#xff1b;使用电脑过程中每分钟都会弹出广告。他为电脑安装了瑞星杀毒软件、奇虎360杀毒软件、360卫士、百度卫士。以及广告神盾&#xff0c;都不能解决…

11 | 排序(上):为什么插入排序比冒泡排序更受欢迎?

划重点&#xff1a;特定算法是依赖特定的数据结构的&#xff0c;带着问题去学习&#xff0c;是最有效的学习方法 本节分析冒泡排序、插入排序、选择排序三种排序算法 如何分析一个排序算法&#xff1f; 分析一个排序算法&#xff0c;要从以下几个方面入手&#xff1a; 排序算…

12 | 排序(下):如何用快排思想在O(n)内查找第K大元素?

算法对比&#xff1a; 算法时间复杂度适合场景冒泡排序、插入排序、选择排序O(n2)小规模数据归并排序、快速排序O(nlogn&#xff09;大规模数据 归并排序和快速排序都用到了分治思想&#xff0c;非常巧妙。我们可以借鉴这个思想&#xff0c;来解决非排序的问题&#xff0c;比如…

13 | 线性排序:如何根据年龄给100万用户数据排序?

三种时间复杂度是 O(n) 的排序算法&#xff1a;桶排序、计数排序、基数排序。因为这些排序算法的时间复杂度是线性的&#xff0c;所以我们把这类排序算法叫作线性排序&#xff08;Linear sort&#xff09;。之所以能做到线性的时间复杂度&#xff0c;主要原因是&#xff0c;这三…

前端学习(1728):前端系列javascript之状态栏分析

<template><view class"content"><view class"todo-header"><view class"todo-header_left"><text class"active-text">全部</text><text>10条</text></view><view class&q…

MySQL索引知识复习

在你享受工作舒适的同时&#xff0c;你的危机也已经在慢慢靠近 正确的创建合适的索引才是保证数据库性能保证的基础 1、索引的底层数据结构&#xff1a;hash&#xff0c;b树&#xff0c;b树的区别&#xff0c;逐层分析为什么最后选用了b树作为索引结构&#xff1f; Mysql数据…

前端学习(1729):前端系列javascript之内容卡片布局

<template><view class"content"><view class"todo-header"><view class"todo-header_left"><text class"active-text">全部</text><text>10条</text></view><view class&q…

面试必问之JVM

Java的一次编译到处运行背后&#xff1a;JVM从软件层面屏蔽了底层硬件、指令字节码的细节&#xff08;JVM充当了适配器的角色和功能&#xff09; JVM\JDK\JRE关系 2、JVM运行时数据区 所有学过的知识是用来推导新的未知的知识的&#xff0c;踏入社会要学会运用自己的知识能力去…

前端学习(1730):前端系列javascript之发布窗口布局上

index.vue <template><view class"content"><view class"todo-header"><view class"todo-header_left"><text class"active-text">全部</text><text>10条</text></view><v…

赵雅智:service_startService生命周期

案例演示 布局文件 <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:tools"http://schemas.android.com/tools"android:layout_width"match_parent"android:layout_height"match_parent"tools:co…

16 | 二分查找(下):如何快速定位IP对应的省份地址?

问题&#xff1a;假设我们有 12 万条这样的 IP 区间与归属地的对应关系&#xff0c;如何快速定位出一个 IP 地址的归属地呢&#xff1f; 二分查找的变形问题&#xff1a; 变体一&#xff1a;查找第一个值等于给定值的元素 public int bsearch(int[] a, int n, int value) {int…

17 | 跳表:为什么Redis一定要用跳表来实现有序集合?

问题&#xff1a;如果数据存储在链表中&#xff0c;就真的没法用二分查找算法了吗&#xff1f;可以对链表进行“改造”&#xff0c;就可以支持类似“二分”的查找算法。 跳表 定义&#xff1a;对链表经过改造之后的数据结构叫做跳表&#xff08;Skip list&#xff09;&#x…

18 | 散列表(上):Word文档中的单词拼写检查功能是如何实现的?

问题引入 在 Word 里输入一个错误的英文单词&#xff0c;它就会用标红的方式提示“拼写错误”&#xff0c;Word 文本编辑器的拼写检查功能是如何实现的呢&#xff1f;散列表&#xff08;Hash Table&#xff09; 散列表 散列表定义&#xff1a;散列表的英文叫“Hash Table”&…

19 | 散列表(中):如何打造一个工业级水平的散列表?

问题引入&#xff1a;如何实现一个工业级的散列表&#xff1f; 主要要求&#xff1a; 设计一个合适的散列函数&#xff1b;定义装载因子阈值&#xff0c;并且设计动态扩容策略&#xff1b;选择合适的散列冲突解决方法。 对于动态散列表来说&#xff0c;不管我们如何设计散列函…