文章目录
2. 栈
栈 是一个遵从 后进先出 原则的有序集合。
2.1 基于数组的 Stack
class Stack {
constructor(){
this.items = [];
}
// 插入元素
push(value){
this.items.push(value);
}
// 删除栈顶元素
pop(){
let val = this.items[this.items.length - 1];
this.items.pop()
return val;
}
// 查看栈顶元素
peek(){
return this.items[this.items.length - 1];
}
// 清空栈
clear(){
this.items = [];
}
// 判空
isEmpty(){
return this.items.length === 0;
}
// 栈的大小
size(){
return this.items.length;
}
}
2.2 基于JS对象的 Stack
this.items = {}; // key:value
}
push(value){
// console.log(typeof this.count);
this.items[this.count] = value;
this.count ++;
}
pop(){
if(this.count === 0){
return undefined;
}
this.count --;
const val = this.items[this.count];
delete this.items[this.count];
return val;
}
peek(){
if(this.count === 0){
return undefined;
}
return this.items[this.count - 1];
}
size(){
return this.count;
}
clear(){
this.items = {};
this.count = 0;
}
isEmpty(){
return this.count === 0;
}
// 数组有自己的toString方法,所以不用关心。
toString(){
if(this.isEmpty()){
return '';
}
let objString = `${this.items[0]}`;
console.log(objString);
for(let i = 1; i < this.count; i ++){
objString = `${objString},${this.items[i]}`
}
return objString;
}
}
2.3 保护数据结构内部元素
let s = new Stack()
s.push(12);
s.push(11);
console.log(s);
console.log(Object.getOwnPropertyNames(s)); // [ 'count', 'items' ]
console.log(Object.keys(s)); // [ 'count', 'items' ]
console.log(s.items); // { '0': 12, '1': 11 }
表明 count
items
属性是公开的,并没有得到保护。
2.3.1 下划线命名约定
class Stack{
constructor(){
this._count = 0;
this._items = {};
}
}
这种方式只是一种约定,不能保护数据。
2.3.2 用ES6的限定作用域 Symbol
实现
const _items = Symbol('stackItems');
class Stack{
constructor(){
// 访问形式!
this[_items] = [];
}
push(value){
this[_items].push(value);
}
}
console.log(_items); // Symbol(stackItems)
console.log(typeof _items); // Symbol
const s = new Stack()
s.push(12);
s.push(223);
console.log(s); // Stack { [Symbol(stackItems)]: [ 12, 223 ] }
let sy = Object.getOwnPropertySymbols(s);
console.log(sy); // [ Symbol(stackItems) ]
console.log(sy[0]); // [ Symbol(stackItems) ]
s[sy[0]].push(88); // Symbol(stackItems) !!! 可以访问到_items
console.log(s); // Stack { [Symbol(stackItems)]: [ 12, 223, 88 ] }
这种方法是一个假的私有属性。
因为Object.getOwnPropertySymbols()
该方法可以取得类里面声明的所有 Symbols
属性。
2.3.3 用ES6的WeakMap
实现类
WeakMap
可以存储键值对。- 实现了真正的属性私有,但是代码可读性不强。
const items = new WeakMap();
class Stack{
constructor(){
items.set(this, []); // key: value | (this: [])
}
push(value){
const s = items.get(this);
s.push(value);
}
pop(){
const s = items.get(this); // typeof s == arr
return s.pop();
}
}
2.4 进制转换
2.4.1 十进制转二进制
function decimalToBinary(value){
const restStack = new Stack(); // 放余数
console.log(restStack);
let number = value;
let rem = 0;
let binaryString = ''
while(number > 0){
rem = Math.floor(number % 2);
number = Math.floor(number / 2);
restStack.push(rem);
}
// output
while(!restStack.isEmpty()){
binaryString += restStack.pop()
}
return binaryString;
}
console.log(decimalToBinary(10));
2.4.2 进制转换算法
/*
params: decValue, base(几进制)
*/
function baseConver(decValue, base){
const restStack = new Stack(); // 放余数
const digitis = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
let number = decValue;
let rem = 0;
let baseString = ''
if(!(base >= 2 && base <= 36)){
return '';
}
while(number > 0){
rem = Math.floor(number % base);
number = Math.floor(number / base);
restStack.push(rem);
}
// output
while(!restStack.isEmpty()){
baseString += digitis[restStack.pop()];
}
return baseString;
}
console.log(baseConver(100345, 35));
console.log(baseConver(16, 4));