栈
前言
数据结构是一个很宽泛的概念,在整个编程语言中,都是很平常的存在。再js中,我们集合数据有对象,有数组,字典,Map... 他们都各有优缺点。如果需要一个满足一定规则的数据结构,就要我们手动去构建,那今天我们就来构建一个栈
什么是栈
栈是一种数据结构,它符合一个规则,后进先出(LIFO)
创建一个基于数组的栈
我们先创建一个类来标识栈
class Stack {
constructor{
this.items = [] // 我们用一个数据结构来保存栈里的数据
}
}
push()
添加一个 或几个新的元素到栈顶
push(el) {
this.items.push(el)
}
pop()
移除栈顶元素,同时返回被删除的元素
pop() {
return this.items.pop()
}
peek()
返回栈顶的元素,不对栈数据做任何修改
peek() {
return this.items[this.items.length - 1]
}
size()
返回栈里的元素个数
size(){
return this.items.length
}
isEmpty()
如果栈里没有元素,就返回true,否则返回falase
isEmpty() {
return this.size === 0
}
clear()
移除栈里所有的元素
clear() {
this.items = []
}
是不是会觉得好简单,确实,数组本身就有长度属性,还有pop,push, 天然的栈数据结构,但是在处理大量数据的时候,我们需要迭代整个数组,直到找到那个元素,并且数组是有序的集合,为了维护元素的排列顺序,也会占用一定的存储空间。所以,我们尝试用对象结构,来实现栈结构
使用对象来实现栈结构,最主要的是需要手动维护对象的长度
创建一个基于对象的栈
我们先创建一个类来标识栈
class Stack {
constructor{
this.items = {} // 我们用一个数据结构来保存栈里的数据
this.count = 0 // 我们得自己维护长度
}
}
push()
添加一个 或几个新的元素到栈顶(添加完记得手动count+1)
push(el) {
this.items[this.count] = el
this.count++
}
pop()
移除栈顶元素,同时返回被删除的元素(对象没有pop,需要手动delete栈顶元素,并且在删除之前,需要count - 1。因为count是从0开始的)
pop() {
if (this.isEmpty()) {
return undefined
}
this.count--
const result = this.items[this.count]
delete this.items[this.count]
return result
}
peek()
返回栈顶的元素,不对栈数据做任何修改(count是从0开始,和length一样,需要 -1)
peek() {
if (this.isEmpty()) {
return undefined
}
return this.items[this.count - 1]
}
size()
返回栈里的元素个数
size(){
return this.count
}
isEmpty()
如果栈里没有元素,就返回true,否则返回falase
isEmpty() {
return this.size() === 0
}
clear()
移除栈里所有的元素
clear() {
this.items = {}
this.count = 0
}
toString 方法
在数组版中,我们不用关心toString方法的实现,因为数组结构可以直接使用数组提供的toString方法,对于对象版本,我们需要实现一个toString方法,来像数组一样打印栈中的内容
toString(){
if (this.isEmpty()) {
return ''
}
let objString = `${this.items[0]}`
for (let k = 1; k < this.count; k++) {
objString = `${objString}, this.items[k]`
}
return objString
}
用栈解决实际问题 从十进制转为二进制
10 / 2 = 5 => rem = 0 将余数放入栈中,0101
5 / 2 = 2 => rem = 1 将余数从栈中弹出 1010
2 / 2 = 1 => rem = 0 入栈终止条件是商是0
1 / 2 = 0 => rem = 1 出栈终止条件是 栈为空
function decimalToBinary(decNumber) {
let binaryString = '';
const remStack = new Stack();
let number = decNumber;
while (number > 0) {
let rem = Math.floor(number % 2);
remStack.push(rem);
number = Math.floor(number / 2);
}
while (!remStack.isEmpty()) {
binaryString += remStack.pop().toString();
}
return binaryString;
}
console.log('decimalToBinary', decimalToBinary(10)); // 1010
十进制转任意(2~36进制)
function baseConverter(decNumber, base) {
let binaryString = '';
let digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
const remStack = new Stack();
let number = decNumber;
if (!(base >= 2 && base <= 36)) {
return '';
}
while (number > 0) {
let rem = Math.floor(number % base);
remStack.push(rem);
number = Math.floor(number / base);
}
while (!remStack.isEmpty()) {
binaryString += digits[remStack.pop()]; // 此处直接去digits取值,所以不用做toString操作
}
return binaryString;
}
console.log('baseConverter', baseConverter(10, 2)); // 1010
console.log('baseConverter', baseConverter(200, 11)); // 172
console.log('baseConverter', baseConverter(100034, 20)); // CA1E
console.log('baseConverter', baseConverter(10000, 30)); // B3A
console.log('baseConverter', baseConverter(100345, 35)); // 2BW0