前端 数据结构 栈与队列
栈
-
栈是一个 后进先出 的数据结构
-
JavaScript 中没有栈这种数据结构,但是可以使用Array 实现栈的所有功能
-
栈的常用操作:
-
入栈 push
-
出栈 pop
-
查看栈顶元素:stack[stack.length-1]
// 声明一个栈 const stack = []; // 入栈 stack.push(1); stack.push(2); // 出栈 const item1 = stack.pop(); const item2 = stack.pop(); //vscode 打断点 左侧查看运行stack 过程
-
-
leetCode 20题 有效的括号
- 解题思路
- 对于没有闭合的左括号而言,越靠后的左括号,对应得右括号越靠前。
- 满足后进先出,考虑用栈。
- 步骤
- 新建一个栈
- 遍历字符串,遇到左括号入栈,遇到和栈顶括号类型匹配的右括号就出栈,类型不匹配直接判定为不合法
- 最后栈空了就合法,否则就不合法
/** * @param { string } * @ return { boolean } **/ var isValid = function(s) { if(s.length %2 === 1) {return false} const stack = []; for(let i=0,length = s.length; i<length; i++){ let c = s[i]; if(c==='(' || c==='{' || c==='['){ stack.push(c); } else { const t = stack[stack.length-1]; if( (t==='(' && c===')') || (t==='[' && c===']') || (t==='{' && c==='}') ){ stack.pop(); }else { return false; } } } return stack.length === 0 }
- 解题思路
-
场景一:十进制转二进制
- 比如:十进制数字35转二进制,35除2取余。
- 后出来的余数反而要排在前面
- 把余数依次入栈,然后再出栈,就可以实现余数倒序输出
-
场景二:有效的括号
()[]{}(()){}
字符串判断是否正确闭合- 越靠后的左括号,对应的右括号越靠前
- 左括号入栈,右括号出栈,最后栈空了就是合法的。
-
场景三: 函数调用堆栈
-
最后调用的函数,是最先执行完的。
-
JS 解释器使用栈来控制函数的调用顺序
function fun1(){ fun2() } function fun2(){ fun3() } function fun3(){ console.log('33') } fun1()// 这里打断点 查看 callStack 进入函数内 看CALLSTACK 内元素的进栈出栈情况
-
队列
-
一个先进先出的数据结构
-
JavaScript 中没有队列,单可以用 Array 实现队列的所有功能
// 声明一个队列 const queue =[]; // 入队 queue.push(1); queue.push(2); // 出队 const item1 = queue.shift(); const item2 = queue.shift();
-
应用场景一:食堂打饭
-
应用场景二:JS异步中的任务队列
-
JS 是单线程,无法同时处理异步中的并发任务。
-
使用任务队列先后处理异步任务
setTimeout( ()=>{ console.log(1) },0); console.log(2); // 执行顺序是 1 2? 还是 2 1
-
js 引擎会去js 任务队列取一个事件去执行
如果有异步操作,就丢给WebAPIs 去执行
WebAPIs 0ms执行完之后的回调函数又放在任务队列中,发现主任务还没有执行完
-
应用场景三:计算最近请求次数 leetCode 993
-
方法ping(int t),其中 t 表示以毫秒为单位的某个时间。返回从3000毫秒前到现在的ping 数。
-
输入:
inputs = [[],[1],[100],[3001],[3002]]
输出:[null,1,2,3,3]
-
有请求就入队,3000ms 前发出的请求出队。
-
队列的长度就是最近请求次数。
var RecentCounter= function(){ this.q = []; } RecentCounter.prototype.ping = function(t){ this.q.push(t) while(this.q[0] < t-3000){ this.q.shit() } return this.q.length }
-