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

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

 

如何实现一个“栈”?

注意:从数组中删除的操作 ,其实并不需要真正的把某个值删除,只要把我们访问下标给减一就可以了。

class Stack {
public:
	int n;
	int count;
	int *data;
	Stack(int num) :n(num),count(0) {
		data = new int[n];
	}
	~Stack(){
		delete data;
	}
	bool push(int k) {
		if (n == count) {
			return  false;
		}
		data[count++] = k;
		return true;
	}
	int pop() {
		if (count == 0)	return 0;
		int t = data[count-1];
		count--;
		return t;
	}
};

int main() {
	return 0;
}

支持动态扩容的顺序栈

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

 

支持动态扩容的栈的push、pop时间复杂度

根据均摊法,前k次入栈直接push,第k+1次入栈,需要把前面k个数据全部进行搬移,所以均摊下到前面k次,每次入栈实际上 是一次直接入栈和一次数据搬移,时间复杂度:O(1)。

疑问:数据搬移的时间复杂度是O(1)吗?

 

  • 栈在函数调用中的应用

每调用一个函数,OS都会分配一块栈空间,用来存储函数调用时的临时变量。

疑问:纠结一个问题,当调用一个函数时候,在栈上开辟一块空间,如果再调用一个函数,那么再开辟一个栈空间,两个空间之间怎么区别开呢?并且在函数中,如果连续两个局部变量存储,它们之间的位置关系是连续的吗?看了下面博客懂了一些,不过还是买到这本书再把这点弄清楚吧。 

https://www.jianshu.com/p/b666213cdd8a

  • 栈在表达式求值中的应用

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

  • 栈在括号匹配中的应用

 

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

我们使用两个栈,X 和 Y,我们把首次浏览的页面依次压入栈 X,当点击后退按钮时,再依次从栈 X 中出栈,并将出栈的数据依次放入栈 Y。当我们点击前进按钮时,我们依次从栈 Y 中取出数据,放入栈 X 中。当栈 X 中没有数据时,那就说明没有页面可以继续后退浏览了。当栈 Y 中没有数据,那就说明没有页面可以点击前进按钮浏览了。

比如你顺序查看了 a,b,c 三个页面,我们就依次把 a,b,c 压入栈,这个时候,两个栈的数据就是图(1);

当你通过浏览器的后退按钮,从页面 c 后退到页面 a 之后,我们就依次把 c 和 b 从栈 X 中弹出,并且依次放入到栈 Y。这个时候,两个栈的数据就是图(2);

这个时候,你通过页面 b 又跳转到新的页面 d 了,页面 c 就无法再通过前进、后退按钮重复查看了,所以需要清空栈 Y。此时两个栈的数据就是图(3)。

 

课后思考:

为什么函数调用要用“栈”来保存临时变量呢?

其实,我们不一定非要用栈来保存临时变量,只不过如果这个函数调用符合后进先出的特性,用栈这种数据结构来实现,是最顺理成章的选择。
从调用函数进入被调用函数,对于数据来说,变化的是什么呢?是作用域。所以根本上,只要能保证每进入一个新的函数,都是一个新的作用域就可以。而要实现这个,用栈就非常方便。在进入被调用函数的时候,分配一段栈空间给这个函数的变量,在函数结束的时候,将栈顶复位,正好回到调用函数的作用域内。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值