什么是栈

栈是一种后进先出,先进后出的数据结构,只允许一端插入和删除数据,在特定的应用场景下 ,当某个数据集合只涉及在一端插入和删除数据,并且满足后进先出,先进后出的特性,就应用选择栈实现

栈的实现: 

栈既可以用数组来实现,也可以用链表实现,分别为顺序栈和链式栈; 

栈的数组实现

package com.zach.geekbang.datastructure.stack;

/**
 * 栈的数组实现
 */
public class ArrayStack {
    private String[] items;
    private int count;//数组中元素的个数
    private int n;

    public ArrayStack(int n) {
        this.items = new String[n];
        this.count = 0;
        this.n = n;
    }

    //入栈操作
    public boolean push(String item) {
        if (n == count)
            return false;
        items[count++] = item;
        return true;
    }
    
    //出栈操作
    public String pop() {
        if(count==0){
            return null;
        }
        
        String tmp = items[count-1];
        count--;
        return tmp;
    }
}

栈的链表实现: 

package com.zach.geekbang.datastructure.stack;

/**
 * 栈基于链表实现
 */
public class StackBaseOnLinkList {
    private Node top;

    public void push(int value) {
        Node newNode = new Node(value, null);
        if (top == null)
            top = newNode;
        else {
            newNode.next = top;
            top = newNode;
        }
    }

    public int pop() {
        if (top == null)
            return -1;
        int value = top.data;
        top = top.next;
        return value;
    }

    private static class Node {
        private int data;
        private Node next;

        public Node(int data, Node next) {
            this.data = data;
            this.next = next;
        }

        public int getData() {
            return data;
        }
    }
}

栈的 操作时间,空间复杂度

无论是顺序栈或链式栈,存储数据只需要一个大小为n的数组,在入栈和出栈过程中,只需要一两个临时变量存储空间,故空间复杂度为O(1);

栈的应用

1. 栈在函数调用中的应用

函数调用栈,操作系统给每个线程分配了一块独立的内存空间,被组织成"栈"这种结构,用来存储函数调用时的临时变量,每进入一个函数,就会将临时变量作为一个栈帧入栈,当被调用函数执行完成,返回之后,将这个函数对应的栈帧出栈

2. 栈在表达式求值中的应用

一则简单的加减乘除的四则运算,如: 34+13*9+44-12/3. 对于四则运算,编译器就是通过两个栈来实现的,其中一个保存操作数的栈,另一个保存运算符的栈,从左向右遍历表达式,当遇到数字,就直接压入操作数栈;当遇到运算符,就与运算符栈的栈顶元素进行比较;如果运算符栈顶元素的优先级高,就将当前运算符压入栈;如果比运算符栈顶元素的优先级低或者相同,从运算符栈中取栈顶运算符,从操作数栈的栈顶取2个操作数,然后进行计算,再把计算完的结果压入操作数栈,继续比较.

3. 如何实现浏览器的前进,后退功能? 

使用两个栈,X和Y,当点击后退按钮时,再依次从栈X中出栈,并将出栈数据依次放入栈Y,当我们点击前进按钮时,依次从栈Y中取出数据,放入栈X中,当栈X中没有数据时,则说明没有页面可以继续浏览后退浏览了,当栈Y中没有数据,那就说明没有页面可以点击前进按钮浏览了.

思考题

1. 函数调用栈来保存临时变量,为什么函数调用"栈"来保存临时变量呢?其他数据结构不行吗?

不一定非要用栈来保存临时变量,只不过如果这个函数调用符合先进先出的特性,用栈这种数据结构来实现,非常适合;从调用函数进入被调用函数,对数据来说,变化的是作用域,所以只要保证每进入一个新的函数,都是一个新的作用域就可以了,用栈实现就方便,在进入被调用函数的时候,分配一段空间给这个函数的变量,在函数结束的时候,将栈顶复位,正好回到调用函数的作用域内.

2. JVM内存管理中有"堆栈"概念,栈内存用来存储局部变量和方法调用,堆内存用来存储Java中的对象,那JVM里面的"栈"和这里说的栈是不是一回事呢,若不是,为什么它也叫作"栈"呢?

内存中的堆栈和数据结构堆栈不是一个概念,可以说内存中的堆栈是真实存在的物理区,数据结构中的堆栈是抽象的数据存储结构。 内存空间在逻辑上分为三部分:代码区、静态数据区和动态数据区,动态数据区又分为栈区和堆区。 代码区:存储方法体的二进制代码。高级调度(作业调度)、中级调度(内存调度)、低级调度(进程调度)控制代码区执行代码的切换。 静态数据区:存储全局变量、静态变量、常量,常量包括final修饰的常量和String常量。系统自动分配和回收。 栈区:存储运行方法的形参、局部变量、返回值。由系统自动分配和回收。 堆区:new一个对象的引用或地址存储在栈区,指向该对象存储在堆区中的真实数据。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zach_ZSZ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值