栈是一种后进先出,先进后出的数据结构,只允许一端插入和删除数据,在特定的应用场景下 ,当某个数据集合只涉及在一端插入和删除数据,并且满足后进先出,先进后出的特性,就应用选择栈实现
栈的实现:
栈既可以用数组来实现,也可以用链表实现,分别为顺序栈和链式栈;
栈的数组实现
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一个对象的引用或地址存储在栈区,指向该对象存储在堆区中的真实数据。