Javascript数据结构——栈

2018-08-06  本文已影响0人  Bingo是谁

1、基于函数,ES5写法

//ES5写法
//基于函数的类
function Stack() {

    let items = [];
    //向栈添加元素
    this.push = function(element){
        items.push(element);
    };
    //从栈移除元素
    this.pop = function(){
        return items.pop();
    };
    //查看栈顶元素
    this.peek = function(){
        return items[items.length-1];
    };
    //检查栈是否为空
    this.isEmpty = function(){
        return items.length == 0;
    };

    this.size = function(){
        return items.length;
    };
    //清空栈元素
    this.clear = function(){
        items = [];
    };
    //打印栈元素
    this.print = function(){
        console.log(items.toString());
    };

    this.toString = function(){
        return items.toString();
    };
}

这种基于函数的类,每次实例化都会重新定义方法,浪费内存

2、基于原型,ES6写法

//ES6写法
//基于原型
class Stack {

    constructor () {
        this.items = [];
    }

    push(element) {
        this.item.push(element);
    }
    ...
}

相当于ES5基于原型的类:

function Stack () {
    this.items = []
}

Stack.prototype = {
    //向栈添加元素
    push: function (element) {
        this.items.push(element)
    },
    ...
}

基于原型的类虽然更省内存,也更适合创建多个实例,却不能声明私有属性(变量)或方法。
可以用ES6的限定作用域Symbol实现类
Symbol

let _items = Symbol();

class Stack2 {

    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] = [];
    }

    print(){
        console.log(this.toString());
    }

    toString(){
        return this[_items].toString();
    }
}

这种方法创建了一个假的私有属性,因为ES6新增的Object.getOwnPropertySymbols方法能够获取到类里面声明的所有Symbol属性名,下面是一个破坏stack类的例子:

let stack = new Stack()
stack.push(5)
stack.push(8)
let objectSymbols = Object.getOwnPropertySymbols(stack)
console.log(objectSymbols .length)  //1
console.log(objectSymbols)  // [Symbol()]
console.log(objectSymbols[0])  // Symbol()
stack[objectSymbols[0].push(1)
stack.print()  //输出 5, 8, 1

3、用ES6的weekMap和闭包实现

WeekMap可以确保属性是私有的

let Stack3 = (function () {

    const items = new WeakMap();

    class Stack3 {

        constructor () {
            items.set(this, []);
        }

        push(element){
            let s = items.get(this);
            s.push(element);
        }

        pop(){
            let s = items.get(this);
            let r = s.pop();
            return r;
        }

        peek(){
            let s = items.get(this);
            return s[s.length-1];
        }

        isEmpty(){
            return items.get(this).length == 0;
        }

        size(){
            let s = items.get(this);
            return s.length;
        }

        clear(){
            items.set(this, []);
        }

        print(){
            console.log(this.toString());
        }

        toString(){
            return items.get(this).toString();
        }
    }

    return Stack3;
})();

缺点:用这种方法的话,扩展类无法继承私有属性。

应用

十进制转二进制

//十进制转二进制
function divideBy2(decNumber) {
    var remStack = new Stack(),
        rem,
        binaryString = '';

    while(decNumber > 0) {
        rem = Math.floor(decNumber % 2);
        remStack.push(rem);
        decNumber = Math.floor(decNumber / 2);
    }

    while(!remStack.isEmpty()) {
        binaryString += remStack.pop().toString();
    }

    return binaryString;
}

十进制转任何进制

//十进制转任何进制
function baseConverter(decNumber, base) {
    var remStack = new Stack(),
        rem,
        baseString = '',
        digits = '0123456789ABCDEF';

    while(decNumber > 0) {
        rem = Math.floor(decNumber % base);
        remStack.push(rem);
        decNumber = Math.floor(decNumber / base);
    }

    while(!remStack.isEmpty()) {
        baseString += digits[remStack.pop()];
    }

    return baseString;
}

平衡括号问题

function parenthesesChecker(symbols){

    let stack = new Stack(),
        balanced = true,
        index = 0,
        symbol, top,
        opens = "([{",
        closers = ")]}";

    while (index < symbols.length && balanced){
        symbol = symbols.charAt(index);
        if (opens.indexOf(symbol) >= 0){
            stack.push(symbol);
            console.log(`open symbol - stacking ${symbol}`);
        } else {
            console.log(`close symbol ${symbol}`);
            if (stack.isEmpty()){
                balanced = false;
                console.log('Stack is empty, no more symbols to pop and compare');
            } else {
                top = stack.pop();
                //if (!matches(top, symbol)){
                if (!(opens.indexOf(top) === closers.indexOf(symbol))) {
                    balanced = false;
                    console.log(`poping symbol ${top} - is not a match compared to ${symbol}`);
                } else {
                    console.log(`poping symbol ${top} - is is a match compared to ${symbol}`);
                }
            }
        }
        index++;
    }
    if (balanced && stack.isEmpty()){
        return true;
    }
    return false;
}

console.log(parenthesesChecker('{([])}')); //true
console.log(parenthesesChecker('{{([][])}()}')); //true
console.log(parenthesesChecker('[{()]')); //false

汉诺塔问题

function towerOfHanoi(n, from, to, helper){

    if (n > 0){
        towerOfHanoi(n-1, from, helper, to);
        to.push(from.pop());
        console.log('-----');
        console.log('Source: ' + from.toString());
        console.log('Dest: ' + to.toString());
        console.log('Helper: ' + helper.toString());
        towerOfHanoi(n-1, helper, to, from);
    }
}

var source = new Stack();
source.push(3);
source.push(2);
source.push(1);

var dest = new Stack();
var helper = new Stack();

towerOfHanoi(source.size(), source, dest, helper);

source.print();
helper.print();
dest.print();
上一篇下一篇

猜你喜欢

热点阅读