一、栈(LIFO)
1、基于数组的栈
-
创建一个类来表示栈
class Stack { constructor() { this.items = []; } } -
向栈添加元素
push(element) { this.items.push(element); } -
从栈移除元素
pop() { return this.items.pop(); } -
查看栈顶元素
peek() { return this.items[this.items.length - 1] } -
检查栈是否为空
isEmpty() { return this.items.length === 0 } -
清空栈元素
clear() { this.items = [] ; }
2、基于JavaScript对象的Stack类
-
声明Stack类
class Stack { constructor() { this.count = 0; this.items = {}; } } -
向栈添加元素
push(element) { this.items[this.count] = element; this.count++; }使用count变量作为items对象的键名,插入的元素则是它的值。
-
验证一个栈是否为空和它的大小
isEmpty() { return this.count === 0; } size() { return this.count; } -
从栈中弹出元素
pop() { if(this.isEmpty()) { return undefined; } this.count--; const result = this.items[this.count]; delete this.items[this.count]; return result; } -
查看栈顶的值和将栈清空
peek() { if(this.isEmpty()) { return undefined; } return this.items[this.count - 1]; } clear() { this.items = {}; this.count = 0; } -
保护数据结构内部元素
在创建别的开发者也可以使用的数据结构或对象时,要保护内部元素,只有我们暴露的方法才能修改内部结构。
-
用ES2015的限定作用域Symbol实现类
ES2015新增一种叫做Symbol的基本类型,它是不可变的,可以用作对象的属性。
const _items = Symbol('stackItems'); class Stack { constructor () { this[_items] = []; } }在上面的代码中,我们声明Symbol类型的变量items,在类的constructor函数中初始化它的值。使用this[_items]访问items。
-
用ES2015的WeakMap实现类
WeakMap可以确保属性是私有的,存储键值对,其中键是对象,值可以使任意数据类型。
const items = new WeakMap(); class Stack() { constructor () { items.set(this, []); } push(element) { const s = items.get(this); s.push(element); } pop() { const s = items.get(this); const r = pop(); return r; } }
-
3、栈的应用
-
函数调用堆栈
-
LeetCode20:有效的括号
-
要求
给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序闭合。
-
示例
输入:s = "()[]{}" 输出:true 输入:s = "([)]" 输出:false -
解法
/** * @param {string} s * @return {boolean} */ var isValid = (s) => { if (s.length % 2 === 1) { return false; } const stack = []; for (let i = 0; i < s.length; i++) { const 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; };
-
2、队列(FIFO)
1、队列数据结构
-
创建队列
class Queue { constructor() { this.count = 0; this.lowestCount = 0; this.items = {}; } } -
向队列添加元素(与Stack类中push方法相同)
enqueue(element) { this.items[this.count] = element; this.count ++; } -
检查队列是否为空和获取它的长度
isEmpty() { return this.count - this.lowestCount === 0; // return this.size() === 0 } size() { return this.count - this.lowestCount; } -
从队列中移除元素
dequeue() { if(this.isEmpty()) { return undefined; } const result = this.items[this.lowestCount]; delete this.items[this.lowestCount]; this.lowestCount++; return result; } -
清空队列
clear() { this.items = {}; this.count = 0; this.lowestCount = 0; }
2、双端队列
-
创建Deque类
class Deque { constructor() { this.count = 0; this.lowestCount = 0; this.items = {}; } } -
向双端队列的前端添加元素
addFront(element) { if(this.isEmpty()) { // 双端队列是空的情况 this.addBack(element); } else if(this.lowestCount > 0) { // 一个元素已经被从双端队列的前端移除 this.lowestCount--; this.items[this.lowestCount] = element; } else { // lowestCount为0,将所有元素后移一位空出第一个位置 for(let i = this.count; i > 0; i--) { this.items[i] = this.items[i-1]; } this.count++; this.lowestCount = 0; this.items[0] = element; } }
3、队列的应用
-
JavaScript中的任务队列
-
LeetCode933:最近的请求次数
-
要求
写一个 RecentCounter 类来计算特定时间范围内最近的请求。
请你实现 RecentCounter 类:
RecentCounter() 初始化计数器,请求数为 0 。 int ping(int t) 在时间 t 添加一个新请求,其中 t 表示以毫秒为单位的某个时间,并返回过去 3000 毫秒内发生的所有请求数(包括新请求)。确切地说,返回在 [t-3000, t] 内发生的请求数。 保证 每次对 ping 的调用都使用比之前更大的 t 值。
-
示例
输入: ["RecentCounter", "ping", "ping", "ping", "ping"] [[], [1], [100], [3001], [3002]] 输出: [null, 1, 2, 3, 3] 解释: RecentCounter recentCounter = new RecentCounter(); recentCounter.ping(1); // requests = [1],范围是 [-2999,1],返回 1 recentCounter.ping(100); // requests = [1, 100],范围是 [-2900,100],返回 2 recentCounter.ping(3001); // requests = [1, 100, 3001],范围是 [1,3001],返回 3 recentCounter.ping(3002); // requests = [1, 100, 3001, 3002],范围是 [2,3002],返回 3 -
解法
var RecentCounter = function () { this.q = []; }; /** * @param {number} t * @return {number} */ RecentCounter.prototype.ping = function (t) { this.q.push(t); while (this.q[0] < t - 3000) { this.q.shift(); } return this.q.length; }; /** * Your RecentCounter object will be instantiated and called as such: * var obj = new RecentCounter() * var param_1 = obj.ping(t) */
-