二、栈结构(Stack)
2.1.简介
数组是一个线性结构,并且可以在数组的任意位置插入和删除元素。而栈和队列就是比较常见的受限的线性结构。如下图所示:
栈的特点为先进后出,后进先出(LIFO:last in first out)。 程序中的栈结构:
- 函数调用栈:A(B(C(D()))):即A函数中调用B,B调用C,C调用D;在A执行的过程中会将A压入栈,随后B执行时B也被压入栈,函数C和D执行时也会被压入栈。所以当前栈的顺序为:A->B->C->D(栈顶);函数D执行完之后,会弹出栈被释放,弹出栈的顺序为D->C->B->A;
- 递归:为什么没有停止条件的递归会造成栈溢出?比如函数A为递归函数,不断地调用自己(因为函数还没有执行完,不会把函数弹出栈),不停地把相同的函数A压入栈,最后造成栈溢出(Stack Overfloat)
栈常见的操作:
- push(element):添加一个新元素到栈顶位置;
- pop():移除栈顶的元素,同时返回被移除的元素;
- peek():返回栈顶的元素,不对栈做任何修改(该方法不会移除栈顶的元素,仅仅返回它);
- isEmpty():如果栈里没有任何元素就返回true,否则返回false;
- size():返回栈里的元素个数。这个方法和数组的length属性类似;
- toString():将栈结构的内容以字符串的形式返回。
2.2.封装栈类
// 栈结构的封装
class Stack {
constructor() {
this.items = [];
}
// push(item) 压栈操作,往栈里面添加元素
push(item) {
this.items.push(item);
}
// pop() 出栈操作,从栈中取出元素,并返回取出的那个元素
pop() {
return this.items.pop();
}
// peek() 查看栈顶元素
peek() {
return this.items[this.items.length - 1];
}
// isEmpty() 判断栈是否为空
isEmpty() {
return this.items.length === 0;
}
// size() 获取栈中元素个数
size() {
return this.items.length;
}
// toString() 返回以字符串形式的栈内元素数据
toString() {
let result = "";
for (let item of this.items) {
result += item + " ";
}
return result;
}
}
// 栈的使用
let s = new Stack()
s.push(20)
s.push(10)
s.push(100)
s.push(77)
console.log(s.pop()); //77
console.log(s.pop()); //100
console.log(s.peek()); //10
console.log(s.isEmpty()); //false
console.log(s.size()); //2
console.log(s.toString()); //20 10
题目
题目来源:leetcode 20. 有效的括号
给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序闭合。
示例 1:
输入:s = "([)]"
输出:false
示例 2:
输入:s = "{[]}"
输出:true
分析
- 从题目中可以看处,字符串
s值包含'(',')','{','}','[',']',当字符串s满足左括号必须用相同类型的右括号闭合并需要按照正确的顺序闭合 - 由于括号闭合顺序是先入后出与栈数据结构一样,因此使用栈数据结构来解决问题,定义
map变量创建栈存储左括号 - 通过
for of遍历字符串s - 当遇到左括号时,通过
push入栈stack - 当与到右括号时,通过
pop出栈stack并判断括号类型是否一样,不一样的话return false - 假设字符串
s为{[()]}
代码实现
/**
* @param {string} s
* @return {boolean}
*/
let isValid = function(s){
let size = s.length
if(size % 2 !== 0) return false
let map = new Map([
["]","["],
[")","("],
["}","{"],
])
let stack = []
for(ch of s){
if(map.has(ch)){
if(!stack.length || stack[stack.length - 1] !== map.get(ch)){
return false
}
stack.pop()
}else{
stack.push(ch)
}
}
return stack.length === 0
}