这是我参与11月更文挑战的第10天,活动详情查看:2021最后一次更文挑战
介绍
栈在编程语言的编译器和内存中保存变量、方法调用等,也被用于浏览器历史记录,是一种在底层比较常用的数据结构,而在js里因为存在好用的数组所代替。但是我们还是要对他进行了解,本期我们就会用普通对象的形式而非数组的形式,手写一个栈的类出来,加深我们的理解。
概念
栈是一种遵从后进先出(LIFO)原则的有序集合。新添加或待删除的元素都保存在栈的同一端,称作栈顶,另一端就叫栈底。在栈里,新元素都靠近栈顶,旧元素都接近栈底。
正文
1.基础结构
我们先看一下,要实现的大体结构与其方法:
const items = new WeakMap();
const count = new WeakMap();
class Stack {
constructor() {
items.set(this, {})
count.set(this, 0)
return this;
}
push(item) {}
pop() {}
peak() {}
clear() {}
size() {}
}
export default Stack;
相信很多同学最先看到的是WeakMap这个ES6新数据结构,我可以知道WeakMap只接受对象作为键名(null除外),不接受其他类型的值作为键名,这样的话,最适合做私有变量了,正是因为保护其内部的参数不被外界破坏,我们就可以用WeakMap去创建出来,当然方法也不唯一的比如Symbol也可以是一个私有变量的实现方案。
好了言归正传,我们创建两个私有变量分别为items元素存储器与count计数器,至于后面的几个方法为:
- push:添加一个新元素到栈顶。
- pop:移除栈顶的元素,同时返回被移除元素的值。
- peek:返回栈顶的元素。
- clear:清除所有栈内的元素。
- size:返回当前栈的元素个数。
接下来我们逐个说一下,怎么来实现。
2.push方法
push(item) {
let _items = items.get(this);
let _count = count.get(this);
_items[_count] = item;
_count += 1;
items.set(this, _items);
count.set(this, _count);
return _count;
}
与数组类似,将传入的元素注入到元素集合中,同时改变计数器。当然这里为了方便计数,我们最后一个元素视为栈顶,第一个元素为栈底。
3.pop&peak
pop() {
let _items = items.get(this);
let _count = count.get(this);
let item = _items[_count-1]
delete _items[_count-1];
_count -= 1;
items.set(this, _items);
count.set(this, _count);
return item;
}
peak() {
let _items = items.get(this);
let _count = count.get(this);
return _items[_count-1];
}
pop为从栈顶拿取并删除这个元素,而peak则不需要删除,但他们都会返回栈顶这个元素。
4.clear&size
clear() {
items.set(this, {});
count.set(this, 0);
}
size() {
return count.get(this);
}
clear清空与size获取长度都很好理解,一个是将元素集合赋空将计数器置零,一个是返回当前计数器的当前值。
5.使用&结果
import Stack from "./js/Stack"
const stack= new Stack();
console.log('push->',stack.push(1));
console.log('push->',stack.push(2))
console.log('push->',stack.push(3))
console.log('pop->',stack.pop());
console.log('peak->',stack.peak());
console.log('clear->',stack.clear())
console.log('size->',stack.size())
我们先推送了123三个值进去,然后分别操作他的pop,peak,clear,size试试看。
我们发现结果都是符合期望的,这样我们就用js普通对象模拟出了一个受保护的栈。
结语
本次我们学习实现了栈这一数据结构。其实栈的实际应用非常广泛。在回溯问题中,它可以存储访问过的任务或路径、撤销的操作。而且在Java和C#用栈来存储变量和方法调用,特别是处理递归算法时,还会抛出一个栈溢出异常,当然这只是冰山一角。数据结构是学习程序的基本功,还有更多的知识等着我们去探索呢~