数组是一种线性结构,并且可以在任意位置插入和删除数据。但是有时候,为了实现某些功能,必须对这种任意性加以限制。栈和队列就是比较常见的受限的线性结构。
栈:Stack,也是一种常见的数据结构。它是一种受限的线性结构,添加和删除元素只能在栈顶操作,后进先出(LIFO,last in first out)。
进栈:向一个栈插入新元素称作进栈(入栈、压栈),它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素。
出栈:从一个栈删除元素称作出栈(退栈),它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。
生活中的栈:
比如:餐厅摞起来的托盘,最后放上去的托盘,往往最先拿出去使用。
程序中的栈:
比如:函数调用栈。例如在函数 A 中调用函数 B,在函数 B 中又调用函数 C。那么在执行过程中,会先将 A 压入栈;在 A 执行的过程中调用了 B,那么会将 B 再压入栈;在 B 执行的过程中又调用了 C,那么会将 C 再压入栈;C 执行完之后,C 出栈;然后 B 执行完,B 出栈;再然后 A 执行完,A 出栈。
栈的实现:
本章基于数组来实现栈结构。
// 封装栈
function Stack() {
// 栈中的元素
this.items = []
}
// 栈中的操作
// 添加一个新元素到栈顶位置
Stack.prototype.push = function(element) {
this.items.push(element)
}
// 移除栈顶的元素,同时返回被移除的元素
Stack.prototype.pop = function() {
return this.items.pop()
}
// 返回栈顶的元素,不对栈做任何修改
Stack.prototype.peek = function() {
return this.items[this.items.length - 1]
}
// 如果栈中没有任何元素就返回 true,否则返回 false
Stack.prototype.isEmpty = function() {
return this.items.length === 0
}
// 返回栈里的元素个数
Stack.prototype.size = function() {
return this.items.length
}
// 将栈结构的内容以字符串形式返回
Stack.prototype.toString = function() {
return this.items.join(' ')
}
// 调用栈
var s = new Stack()
s.push(20)
s.push(10)
console.log(s.toString())
栈的应用:
十进制转二进制:因为二进制是满二进一,因此要把十进制转为二进制,可以将该十进制数字和 2 整除,直到结果是 0 为止,从下到上的余数的组合即是最终的结果。
因为最后计算得到的余数要最先取出来用,因此可以使用栈来实现十进制转二进制。
// 将十进制转为二进制
function dec2bin(decNumber) {
// 定义栈对象
var s = new Stack()
// 循环操作
while(decNumber > 0) {
// 获取余数,并且放入到栈中
s.push(decNumber % 2)
// 获取整除后的结果,作为下一次运行的数字
decNumber = Math.floor(decNumber / 2)
}
// 从栈中取出值
var binaryString = ''
while(!s.isEmpty()) {
binaryString += s.pop()
}
return binaryString
}
console.log(dec2bin(100)) // 1100100