栈:是一种遵循先进后出(LIFO Last In First Out)原则的有序集合。新添加或待删除的元素都保存在栈的同一端,称作栈顶,另一端就叫栈底
1.创建一个基于数组的栈
push: 添加一个(或几个)新元素到栈顶
pop:移除栈顶的元素,同时返回被移除的元素
peek:返回栈顶的元素,不对栈做任何修改
isEmpty: 如果栈里没有任何元素就返回true, 否则返回false
size: 返回栈里的元素个数
clear: 移除栈里的所有元素
两种方式:
function Stack() {
this.items = []
Stack.prototype.push = (element) => {
this.items.push(element)
}
Stack.prototype.pop = () => {
return this.items.pop()
}
Stack.prototype.peek = () => {
return this.items[this.items.length - 1]
}
Stack.prototype.isEmpty = () => {
return this.items.length === 0
}
Stack.prototype.size = () => {
return this.items.length
}
Stack.prototype.clear = () => {
this.items = []
}
}
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
}
size() {
return this.items.length
}
clear() {
this.items = []
}
}
使用 Stack 类
const stack = new Stack()
stack.push(2)
stack.push(4)
stack.isEmpty()
stack.pop()
stack.peek()
stack.size()
stack.clear()
2.创建一个基于 JavaScript 对象的 Stack 类
基于对象与基于数组两种方式创建Stack
对比:相对于对象,使用数组时,大部分方法的时间复杂度是O(n),且数组是一个有序集合,为了保证元素排列有序,它会占用更多的内存空间。
class Stack {
constructor() {
this.items = {}
this.count = 0
}
push(element) {
this.items[this.count] = element
this.count++
}
size() {
return this.count
}
isEmpty() {
return this.count === 0
}
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
}
// 以字符串形式返回栈的内容
toString() {
if (this.isEmpty()) {
return ''
}
let objString = `${this.items[0]}`
for (let i = 1; i < this.count; i++) {
objString = `${objString},${this.items[i]}`
}
return objString
}
}
用栈解决问题(实现从十进制转二进制)
function decimalToBinary(decNumber) {
const remStack = new Stack()
let number = decNumber
let rem
let binaryString = ''
while (number > 0) {
rem = Math.floor(number % 2)
remStack.push(rem)
number = Math.floor(number / 2)
}
while (!remStack.isEmpty()) {
binaryString += remStack.pop().toString()
}
return binaryString
}
进制转换算法(将十进制转换成基数为2~36的任意进制)
/**
* @method
* @param descNumber {Number} 十进制数字
* @param base {Number} 十进制数字
* @returns {String} base进制值
* @desc 进制转换算法(将十进制转换成基数为2~36的任意进制)
*/
function baseConverter(descNumber, base) {
const remStack = new Stack()
const digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
let number = descNumber
let rem
let baseString = ''
if (!(base >= 2 && base <= 36)) {
return ''
}
while (number) {
rem = Math.floor(number % base)
remStack.push(rem)
number = Math.floor(number / base)
}
while (!remStack.isEmpty()) {
baseString += digits[remStack.pop()]
}
return baseString
补充
new 运算符调用函数的具体过程:
- 创建一个空对象,将空对象的
_proto_
成员指向构造函数的prototype
; - 把上面创建的空对象赋值赋值构造函数内部的
this
,用构造函数内部的方法修改空对象; - 如果构造函数中没有返回其它对象,那么返回
this
,即创建的这个新对象;否者返回构造函数返回的对象;
function new(fn, ...args) {
if(typeof fn !== 'function' ) {
throw 'new function the first param must be a function'
}
const obj = Object.create(fn.prototype);
const result = fn.apply(obj, args);
if(result && (typeof result === 'object' || typeof result === 'function')) {
return result;
}
return obj;
}
Object.create() 的实现
Object.create()
会将参数对象作为一个新创建的空对象的原型, 并返回这个空对象。
// 简略版
function create(obj) {
// 新声明一个函数
function C(){};
// 将函数的原型指向 obj
C.prototype = obj;
// 返回这个函数的实例化对象
return new C()
}
// 升级版
object.create = function (proto, propertyObject = undefined) {
if(typeof proto !== 'object' && typeof proto !== 'function') {
throw new Error();
} else if(proto === null) {
throw new Error();
}
function F(){};
F.prototype = proto;
const obj = new F();
if(propertyObject !== undefined) {
// Object.defineProperties(obj, props)
// 方法直接在一个对象上定义新的属性或修改现有属性,并返回该对象。
Object.defineProperties(obj, propertyObject)
}
return obj;
}