3.数据结构-栈结构

  数组回顾

  JS的数组就是API的调用:

   因此,不讲

  补充:普通语言的数组封装(比如Java的ArrayList)

    常见语言的数组不能存放不同的数据类型,因此所有在封装时通常存放在数组中的时Object类型

    常见语言的数组容量不会自动改变.(需要进行扩容操作)

    常见语言的数组进行中间插入和删除操作性能比较低

  认识栈结构

  栈也是一种 非常常见 的数据结构,并且在程序中的 应用非常广泛

  数组

    我们知道数组是一种线性结构,并且可以在数组的 任意位置 插入和删除数据.

    但是有时候,我们为了实现某些功能,必须对这种任意性 加以 限制.

    而 栈和队列 就是比较常见的 受限的线性结构,我们先来学习栈结构.

  栈结构示意图

    

 

  栈(stack),它是一种受限的线性表,后进先出(FIFO)

    其限制是仅允许在 表的一端 进行插入和删除运算。这一端被称为栈顶,相对地,把另一端称为栈底

    LIFO(last in first out)表示就是后进入的元素,第一个弹出栈空间。类似于自动餐托盘,最后放上的托盘,往往先把拿出去使用。

    向一个栈插入新元素又称作进栈、入栈压栈,它是把新元素放到栈顶元素上面,使之成为新的栈顶元素;

    从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。

  生活中类似于栈的

    自助餐的托盘,最新放上去的,最新被客人拿走使用的。

    收到很多的邮件(实体的),从上往下依次处理这些邮件。(最新到的邮件,最先处理)

    注意:不允许改变邮件的次序,比如从最小开始,或者处于最紧急的邮件,否则就不再是栈结构了。而是队列或者优先级队列结构。

  栈的应用

    程序中什么是使用栈实现的呢?
      学了这么久的编程,是否听说过,函数调用栈呢?

      我们知道函数之间和互相调用:A调用B,B中又调用C,C中又调用D。

      那样在执行的过程中,会先将A压入栈,A没有执行完,所有不会弹出栈。

      在A执行的过程中调用了B,会将B压入栈,这个时候B在栈顶,A在栈底。

      如果这个时候B可以执行完,那么B会弹出栈。但是B有执行完吗?没有,它调用了C。

      所以C会压栈,并且在栈顶。而C调用了D,D会压入到栈顶。

      所以当前的栈顺序是:栈顶A->B->C->D栈顶。

      D执行完,弹出栈。C/B/A依次弹出栈。

      所以我们有函数调用栈的称呼,就来自于它们内补的实现机制。 (通过栈来实现的)

  函数调用栈的示意图

    

 

 

   栈结构面试题

     面试题目:

      

 

    题目答案:C

      A答案:65进展,5出栈,4进栈出栈,3进栈出栈,6出栈,21进栈,1出栈,2出栈

      B答案:654进栈,4出栈,5出栈,3进栈出栈,2进栈出栈,1进栈出栈,6出栈

      C答案:65432进栈,2出栈,3出栈,4出栈,1进栈出栈,5出栈,6出栈

  栈结构的实现

    实现栈结构有两种比较常见的方式:

      基于数组实现

      基于链表实现

    什么是链表?

      也是一种数据结构,目前我们还没有学习,并且JavaScript中并没有自带链表结构。

      后续,我们会自己来实现链表结构,并且对比数组和链表的区别

    因此,我们这里实现的栈结构基于数组。

  栈结构的封装

    <script>
        // Method:和某一个对象实例有联系
        // function
        // 封装栈类
        function Stack() {
            // 栈中的属性
            this.items = [];
            // 栈的操作
            // 1.将元素压入栈
            // 1.1 this.push = function() {}
            // 1.2 好处内存利用小
            Stack.prototype.push = function(element) {
                    this.items.push(element)
                }
                // 2.从栈中取出元素
            Stack.prototype.pop = function() {
                    return this.items.pop()
                }
                // 3.查看一下栈顶元素
            Stack.prototype.peek = function() {
                    return this.items[this.items.length - 1]
                }
                // 4.判断栈是否为空
            Stack.prototype.isEmpty = function() {
                    return this.items.length == 0
                }
                // 5.获取栈中元素的个数
            Stack.prototype.sizi = function() {
                    return this.items.length
                }
                // 6.toString方法
            Stack.prototype.toString = function() {
                // 20 10 12 8 7
                var result = ''
                for (var i = 0; i < this.items.length; i++) {
                    result += this.items[i] + ''
                }
                return result
            }
        }
        // 栈的使用
        var s = new Stack();
        // 1.将元素压入栈
        s.push(20);
        s.push(10);
        s.push(12);
        s.push(8);
        s.push(7);
        console.log(s);
        // 2.从栈中取出元素
        s.pop();
        s.pop();
        console.log(s);
        // 3.查看一下栈顶元素
        console.log(s.peek());
        // 4.判断栈是否为空
        console.log(s.isEmpty());
        // 5.获取栈中元素的个数
        console.log(s.sizi());
        // 6.toString方法
        console.log(s.toString());
    </script>

  栈的操作

    栈常见有哪些操作呢?

      push(element):添加一个新元素到栈顶位置。

      pop():移除栈顶的元素,同时返回被移除的元素。

      peek():返回栈顶的元素,不对栈做任何修改(这个方法不会义出栈顶的元素,仅仅返回它)。

      isEmpty():如果栈里没有任何元素就返回true,否则返回false。

      size():返回栈里的元素个数。这个方法和数组的length属性很类似。

      toString():将栈结构的内容以字符形式返回。

    现在,我们可以在类中一一实现这些方法。

  十进制转二进制

    我们已经学会了如何使用Stack类,现在就用它解决一些计算机科学中的问题。

    为什么需要十进制转二进制?

      现实生活中,我们主要使用十进制。

      但在计算科学中国,二进制非常重要,因为计算机里的所有内容都是用二进制数字表示的(0和1).

      没有十进制和二进制互相转化的能力,与计算机交流就很困难。

    如何实现十进制转二进制?

      要把十进制转化二进制,我们可以将该十进制数字和2整除(二进制是慢二进一),知道结果是0为位置。

      举个例子,把十进制的数字10转化成二进制的数字,过程大概是这样:

      

  栈-十进制转二进制代码:

    

<script>
        // Method:和某一个对象实例有联系
        // function
        // 封装栈类
        function Stack() {
            // 栈中的属性
            this.items = [];
            // 栈的操作
            // 1.将元素压入栈
            // 1.1 this.push = function() {}
            // 1.2 好处内存利用小
            Stack.prototype.push = function(element) {
                    this.items.push(element)
                }
                // 2.从栈中取出元素
            Stack.prototype.pop = function() {
                    return this.items.pop()
                }
                // 3.查看一下栈顶元素
            Stack.prototype.peek = function() {
                    return this.items[this.items.length - 1]
                }
                // 4.判断栈是否为空
            Stack.prototype.isEmpty = function() {
                    return this.items.length == 0
                }
                // 5.获取栈中元素的个数
            Stack.prototype.sizi = function() {
                    return this.items.length
                }
                // 6.toString方法
            Stack.prototype.toString = function() {
                // 20 10 12 8 7 
                var result = ''
                for (var i = 0; i < this.items.length; i++) {
                    result += this.items[i] + ''
                }
                return result
            }
        }
         // 函数:将十进制转成二进制
        function dec2bin(decNumber) {
            // 1.定义栈对象
            var stack = new Stack();
            // 2.循环操作
            while (decNumber > 0) {
                // 2.1.获取余数,并且放入到栈中
                stack.push(decNumber % 2);
                // 2.2.获取整除后的结果,作为下一次运行的数字
                decNumber = Math.floor(decNumber / 2);
            }
            // 3.从栈中取出0和1
            var binary = '';
            while (!stack.isEmpty()) {
                binary += stack.pop();
            }
            return binary
        }
        // 测试十进制转二进制的函数
        console.log(dec2bin(100));
        console.log(dec2bin(10));
        console.log(dec2bin(1000));
    </script>

  

 

 

 

 

 

 

 

 

 

    

 

posted @ 2022-03-24 14:39  风太温柔  阅读(38)  评论(0编辑  收藏  举报