JavaScript模拟一个栈

372 阅读5分钟

0 什么是栈

栈又名堆栈,是一中数据结构,只允许在一端进行数据的添加或者删除,这一端被称为栈顶,相对地,把另一端称为栈底。因而按照后进先出(LIFO, Last In First Out)的原理运作

  • 示意图

特点

  • 后进先出
  • 最新的元素越靠近栈顶,越旧的越靠近栈底

1 es5实现栈

1.1 定义

    //栈类
    function Stack () {
        //1 声明数组,保存栈里的元素,栈底:数组的开头位置; 栈顶:数组的末尾位置
        let items = []

        //2 声明栈的方法
        //添加元素到栈顶,添加元素到数组的末尾
        this.push = function ( ele ) {
            items.push ( ele )
        }
        //移出栈顶元素,移出数组最后一个元素
        this.pop = function () {
            items.pop ()
        }
        //返回栈顶元素
        this.peek = function () {
            return items[ items.length - 1 ]
        }
        //检测栈中是否有元素,没有返回true,有返回false
        this.isEmpty = function () {
            return items.length == 0
        }
        //清空栈中的所有元素
        this.clear = function () {
            items.length = 0
        }
        //返回栈中元素个数
        this.size = function () {
            return items.length
        }
        //打印栈里的元素到控制台
        this.print = function () {
            console.log ( items.toString () )
        }
    }

1.2 使用

    //2 使用栈
    let stack1 = new Stack();//创建栈对象
    console.log ( stack1.isEmpty () );//true,因为没有添加元素进去
    
    stack1.push(3);//往栈中添加元素
    stack1.push(5);//
    console.log ( stack1.peek() );//取出栈顶元素,打印5
    
    stack1.push(11);
    console.log ( stack1.size () );//3
    console.log ( stack1.isEmpty () );//false
    
    stack1.push(15);
    
    stack1.pop();
    stack1.pop();
    
    console.log ( stack1.size () );//size=2 ,因为15,11已经被移出栈了
    stack1.print();

2 es6实现栈

2.1 定义

    //用ECMAScript6语法实现的栈类
    let Stack2 = (function () {
        const items = new WeakMap();

        class Stack2 {
            constructor (){
                items.set(this,[]);
            }
            push(ele){
                let s = items.get(this);
                s.push(ele);
            }
            pop(){
                 let s = items.get(this);
                 return s.pop();
            }
            peek(){
                 let s = items.get(this);
                 return s[s.length-1];
            }
            isEmpty(){
                 let s = items.get(this);
                 return s.length==0;
            }
            clear(){
                 let s = items.get(this);
                 s = [];
            }
            size(){
                 let s = items.get(this);
                 return s.length;
            }
            print (){
                let s = items.get(this);
                console.log ( s.toString () );
            }


        }
        return Stack2;
    }());

2.2 使用

    let stack2 = new Stack2();//创建栈对象
    console.log ( stack2.isEmpty () );//true,因为没有添加元素进去

    stack2.push(3);//往栈中添加元素
    stack2.push(5);//
    stack2.print();
    console.log ( stack2.peek() );//取出栈顶元素,打印5

    stack2.push(11);
    console.log ( stack2.size () );//3
    console.log ( stack2.isEmpty () );//false

    stack2.push(15);
    stack2.print();
    stack2.pop();
    stack2.pop();

    console.log ( stack2.size () );//size=2 ,因为15,11已经被移出栈了
    stack2.print();

3 应用 使用栈进行进制转换

3.1 十进制转换为二进制数

比如十进制的12转换为二进制的12 12/2=6 余数=0 6/2=3 余数=0 3/2=1 余数=1 1/2=0 余数=1

对应的二进制为余数的倒置,即是1100

思路:

  1. 将十进制数对2求余数,将余数压入栈中
  2. 再计算十进制数除以2的结果
  3. 判断结果是否大于0,如果大于,重复步骤1和步骤2
  4. 取出栈中数据,拼接为一个字符串
    function dec2Binary ( decNumber ) {
        let stack1 = new Stack();
        let rem;//10对2求的余数
        let binaryStr = "";//存储二进制字符串

        //十进制数除以2,获取余数,存储到栈中,知道该数小于等于0,结束
        while(decNumber>0){
            rem = Math.floor(decNumber%2);
            stack1.push(rem);
            decNumber = Math.floor(decNumber/2);
        }

        //取出栈里的数,拼接为二进制字符串
        while(!stack1.isEmpty()){
            binaryStr+=stack1.pop()+"";
        }
        return Number(binaryStr);

    }
    console.log ( dec2Binary ( 12 ) );

3.2 十进制转换成任意进制

十进制=>二进制 余数有0,1 十进制=>八进制 余数有0,1,2,3,.....7 十进制=>十六进制 余数有0,....9,A,B,C,D,E,F

    /**
     * @param decNumber 十进制数
     * @param base 进制
     * @return {string} 转换为base进制的数的字符串
     */
    function dec2AnyNum ( decNumber,base ) {
        let stack1 = new Stack();
        let rem=undefined;
        let tempStr = "";//存储转换后的对应进制字符串
        let number = "0123456789ABCDEF";//16进制内的余数

        //十进制转换为base进制,存储到stac1中
        while(decNumber>0){
            rem = Math.floor(decNumber%base);
            stack1.push(rem);
            decNumber = Math.floor(decNumber/base);
        }

        //base进制数,拼接为字符串
        while ( !stack1.isEmpty() ) {
            tempStr+= number[stack1.pop()];
        }
        return tempStr;
    }

验证:

console.log ( dec2AnyNum ( 12, 16 ) );

3.3 二进制转换为十进制

1100(2) 二级制的12,转换为十进制的过程(公式) 1100,从栈顶取出就是0-0-1-1(2) = 12^3 + 12^2 + 02^1+02^0=8+4+0+0=12

思路:

  1. 将二进制数据转为为单个字符串,存储到数组中
  2. 将数组中的值全部压入栈中
  3. 循环取出栈顶的数据,对该数据进行进制转换计算(数据*2^次方)

注意:根据栈的特性,从栈顶取出数据的顺序和原始数据顺序相反, 如1100,从栈顶取出就是0-0-1-1

    function bin2Dec ( binNumber ) {
        let stack1 = new Stack();
        let rem = undefined;
        let tempNum = 0;

        var binNumberArr = (new String(binNumber)).split("");

        binNumberArr.forEach(function ( ele ) {
            stack1.push(ele);
        });

        var bin = 0;//幂数
        while(!stack1.isEmpty()){
            tempNum+= stack1.pop()*Math.pow(2,bin);//Math.pow(2,bin) 2的bin次方
            bin++;
        }
        return tempNum;
    }

验证:

console.log ( bin2Dec ( 1100 ) );

3.4 任意进制转换为十进制

  1. 准备一个0-16的映射表对象
  2. 数字变为单个字符串,存储到数组中
  3. 数组的元素压入栈
  4. 取出栈顶元素,通过通过映射表[元素]取得对应的数,再进行计算
    /**
     * @param anyNumber currentBase进制的整数
     * @param currentBase 进制
     * @return {number} 返回计算以后的十进制数
     */
    function anyNum2Dec ( anyNumber,currentBase ) {
        let stack1 = new Stack();
        let tempNum = 0;

        //16进制数和十进制映射表
        let number = {
            "0":0,
            "1":1,
            "2":2,
            "3":3,
            "4":4,
            "5":5,
            "6":6,
            "7":7,
            "8":8,
            "9":9,
            "A":10,
            "B":11,
            "C":12,
            "D":13,
            "E":14,
            "F":15
        };
        
        //数字转换字符串,并储存为数组的元素
        var anyNumberArr = (anyNumber+"").split("");

        anyNumberArr.forEach(function ( ele ) {
            stack1.push(ele.toUpperCase());
        });

        var bin = 0;//幂数
        while(!stack1.isEmpty()){
            tempNum+= number[stack1.pop()]*Math.pow(currentBase,bin);//Math.pow(2,bin) 2的bin次方
            bin++;
        }
        return tempNum;
    }

验证:

    console.log ( anyNum2Dec ( "3c",16 ) );

3.5 任意进制转换

思路:当前进制先转换为十进制数,十进制数转换为目标进制

    function anyDecimalConversion (num,srcDec,destDec  ) {
        //srcDec转换为十进制的数
        let decNum = anyNum2Dec(num,srcDec);
        //十进制的srcDec 转换为 destDec进制数
        return dec2AnyNum(decNum,destDec);
    }

验证:

    console.log ( anyDecimalConversion ( "abcde", 16,8 ) )