【JS】数据结构之栈

基本介绍

内存中的堆栈和数据机构中的堆栈不是一个概念,内存中的堆栈是真实存在的物理区,数据结构中的堆栈是抽象数据存储结构。

  • 栈:是一种受限制的线性表。他遵循后进先出的原则(LIFO)
  • 其限制是仅允许在表的一端进行插入和删除运算,这一端被称为栈顶,相对的另一端称为栈底。
  • 最开始的时候,栈是不含有任何数据的,叫做空栈。
  • 向一个栈插入新元素称为入栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素。
  • 从一个栈删除元素又称之为出栈,他是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。

在这里插入图片描述

我们可以利用栈这个数据结构,理解JS的运行机制之:JS调用栈

  • 执行上下文:就是当前JS代码被解析和执行所在环境的抽象概念。
  • JS中任何代码都是在执行上下文中运行的(执行环境)
  • JS 执行上下文分三种:
1. 全局执行上下文:先创建全局对象,再将this指向这个全局对象。
2. 函数执行上下文:每次调用函数的时候,会为这个函数创建一个新的执行上下文。
3. Eval函数执行上下文:`eval()`
  • 示例:
const one = () => {
	two();
	console.log('我是one');
}
const two = () => {
	console.log('我是two');
}
one();
  • JS引擎创建一个新的全局执行上下文,并将这个执行上下文推入当前的执行栈中。
  • 执行栈用于存储在代码执行期间创建的所有的执行上下文。
- 每当发生函数调用的时候,JS引擎都会为该函数创建一个新的执行上下文并push到当前执行栈的栈顶。
- 当调用 one 函数的时候,JS引擎都会为该函数创建一个新的执行上下文并推到当前执行栈的栈顶。
- 当调用 two 函数的时候,JS引擎都会为该函数创建一个新的执行上下文并推到当前执行栈的栈顶。
- 当two函数调用完毕后,他的执行上下文就会从当前执行栈中弹出,上下文的控制权移到当前执行栈中的下一个执行上下文:one 函数

我们可以利用栈这个数据结构,理解JS的运行机制之:递归的原理

  • 函数的调用本质:入栈和出栈操作。
  • 但是函数在调用栈里面有个特例,那就是递归(自己调自己)。
  • 先进栈,到条件后再出栈,如果不出栈,就会导致:栈溢出(栈的容量是有限的)
  • 示例:阶乘n!(5! = 54321)
const factor = (n)=>{
	// 递归要有出口,否则就是死循环
	if(n === 1){
		return 1;
	}
	return n * factor(n - 1);
}
console.log(factor(3));	// 6
console.log(factor(10));	// 3628800
  • 函数在内存中调用,会形成一个调用记录,又称为调用帧
  • 递归可能需要同时保存成百上千个调用帧,很容易发生栈溢出。
  • 但是对于尾递归来说,由于只存在一个调用栈,所有不会发生栈溢出错误
// 尾调用
function a(x){}
function b(x){
	return a(x);
}
// 尾调用自身就是尾递归
const factor = (n, total)=>{
	if(n === 1){
		return total;
	}
	return factor(n - 1, n * total);
}
  • 示例:斐波那契数列(从第三项开始,每一项等于前两项的和:1,1,2,3,5,8,13)
// 递归
const Fibonacci = (n) => {
	if(n<=1){
		return 1;
	}
	return Fibonacci(n-1)+Fibonacci(n-2);
}
/*
	会存在一个重复计算问题
	n = 5, Fibonacci(4)+Fibonacci(3)
	n = 4, Fibonacci(3)+Fibonacci(2)
	...
*/
console.log(Fibonacci(50));	// 运行直接卡死
// 尾递归
// 把前面2位数,当作参数传进来
const Fibonacci = (n, ac1=1, ac2=1) => {
	if(n<=1){
		return ac2;
	}
	return Fibonacci(n-1, ac2, ac1+ac2);
}
console.log(Fibonacci(50));	// 运行就很流畅

代码实现

栈的应用有:十进制转二进制

  • 使用JavaScript实现一个栈结构
class Stack{
	constructor() {
		this.items = [];
	}
	// 入栈
	push(ele){
		this.items.push(ele);
	}
	// 出栈
	pop() {
		return this.items.pop();
	}
	// 获取栈顶元素
	peek(){
		return this.items[this.items.length - 1];
	}
	// 查看栈是否为空
	isEmpty(){
		return this.items.length === 0;
	}
	// 查看栈中元素个数
	size(){
		return this.items.length;
	}
	// 清空栈
	clear(){
		this.items = []
	}
}

const stack = new Stack();
stack.push(1);
stack.push(2);
stack.push(3);
stack.push(4);

console.log(stack);

// 十进制转二进制
const binary = (number) =>{
	let stack = new Stack();
	let remainder = 0;
	let top = '';
	while(number > 0){
		// 除于2取余数
		remainder = number % 2;
		stack.push(remainder);
		// 向下取整
		number = Math.floor(number / 2);
	}
	// 不为空的时候
	while(!stack.isEmpty()){
		// 栈顶元素
		top += stack.pop();
	}
	return top;
}
console.log("2 = ", binary(2))

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一颗不甘坠落的流星

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值