美文网首页
Javascript数据结构——栈

Javascript数据结构——栈

作者: Bingo是谁 | 来源:发表于2018-08-06 20:51 被阅读0次

    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();
    

    相关文章

      网友评论

          本文标题:Javascript数据结构——栈

          本文链接:https://www.haomeiwen.com/subject/jfxgvftx.html