栈简介
- 栈的英文为(stack)。
- 栈是一个**先入后出(FILO-First In Last Out)**的有序列表。
- 栈(stack)是限制线性表中元素的插入和删除只能在线性表的同一端进行的一种特殊线性表。允许插入和删除的一端,为变化的一端,称为栈顶(Top),另一端为固定的一端,称为栈底(Bottom)。
- 根据栈的定义可知,最先放入栈中元素在栈底,最后放入的元素在栈顶,而删除元素刚好相反,最后放入的元素最先删除,最先放入的元素最后删除。
- 将栈想象后成枪的弹匣,子弹只能从上面进从上面出,且先进去的子弹后打出来,后进去的子弹先打出来。
栈的应用场景
- 子程序的调用:在跳往子程序前,会先将下个指令的地址存到堆栈中,直到子程序执行完后再将地址取出,以回到原来的程序中。
- 处理递归调用:和子程序的调用类似,只是除了储存下一个指令的地址外,也将参数、区域变量等数据存入堆栈中。
- 表达式的转换[中缀表达式转后缀表达式]与求值。
- 二叉树的遍历。
- 图形的深度优先(depth一first)搜索算法。
下面分别介绍用数组和链表实现栈结构
一、使用数组模拟栈
数组模拟栈分析
1)定义一个长度为maxSize的数组data[maxSize]
2)定义一个变量top表示栈顶,初始值为-1
3)入栈操作:top++;data[top] = value;
4)出栈操作:value = data[top];top–;return value;
5)判空:top == -1
6)判满:top == maxSize-1
代码示例
1.创建一个ArrayStack类,表示由数组实现的栈
ArrayStack
/**
* 定义一个ArrayStack类表示栈
*/
class ArrayStack {
// 存放数据
private int[] data;
// 栈的大小
private int maxSize;
// 栈顶
private int top = -1;
public ArrayStack(int capacity) {
this.maxSize = capacity;
data = new int[capacity];
}
// 判断栈满
public boolean isFull() {
return top == maxSize - 1;
}
// 判断栈空
public boolean isEmpty() {
return top == -1;
}
// 入栈
public void push(int value) {
if (isFull()) {
System.out.println("栈满");
return;
}
top++;
data[top] = value;
}
// 出栈,将栈顶的数据返回
public int pop() {
// 判空
if (isEmpty()) {
throw new RuntimeException("栈为空");
}
return data[top--];
}
// 遍历栈,从栈顶开始遍历
public void showStack() {
for (int i = top; i >= 0; i--) {
System.out.println(data[i] + "\t");
}
}
}
测试
public class ArrayStackDemo {
public static void main(String[] args) {
// 创建一个栈
ArrayStack arrayStack = new ArrayStack(5);
Scanner scanner = new Scanner(System.in);
Scanner scanner1 = new Scanner(System.in);
boolean loop = true;
while (loop) {
System.out.println("push(入栈),pop(出栈),show(显示栈),exit(退出程序)");
String key = scanner.nextLine();
switch (key) {
case "push":
System.out.print("请输入一个数:");
int value = scanner1.nextInt();
arrayStack.push(value);
break;
case "pop":
System.out.println("出栈:" + arrayStack.pop());
break;
case "show":
System.out.println("显示栈:");
arrayStack.showStack();
break;
case "exit":
System.out.println("退出程序:");
loop = false;
}
}
}
}
控制台输出
push(入栈),pop(出栈),show(显示栈),exit(退出程序)
push
请输入一个数:100
push(入栈),pop(出栈),show(显示栈),exit(退出程序)
push
请输入一个数:200
push(入栈),pop(出栈),show(显示栈),exit(退出程序)
push
请输入一个数:300
push(入栈),pop(出栈),show(显示栈),exit(退出程序)
show
显示栈:
300
200
100
push(入栈),pop(出栈),show(显示栈),exit(退出程序)
pop
出栈:300
push(入栈),pop(出栈),show(显示栈),exit(退出程序)
show
显示栈:
200
100
push(入栈),pop(出栈),show(显示栈),exit(退出程序)
exit
退出程序:
二、使用链表模拟栈
链表模拟栈分析
- 为了方便倒序遍历,使用双向链表来实现栈结构。
- 定义一个节点bottom表示栈底,定义一个节点top表示栈顶,初始值都为null。
- 入栈时,如果是第一次入栈,将节点赋值给bottom和top;之后再入栈就创建新节点并赋值给top,将top添加到链表尾部。
- 出栈时,从链表尾部删除一个节点
5)判空:当bottom == null时,链表为空
6)判满:因为只要内存足够,链表可以无限延长,所以不需要有判满操作
代码示例
- 创建LinkedListStack类,表示由链表实现的栈
LinkedListStack
class LinkedListStack {
Node bottom;
Node top;
public LinkedListStack() {
}
public boolean isEmpty() {
return bottom == null;
}
// 压栈操作
public void push(int value) {
Node node = new Node(value);
// 如果bottom为null,说明链表长度为0,此时需要给bottom赋值,让它成为栈底
// 否者说明链表已经有节点,直接在链表末尾(栈顶)插入新节点即可
if (isEmpty()) {
bottom = node;
top = node;
} else {
node.setPrev(top);
top.setNext(node);
top = node;
}
}
// 出栈操作
public int pop() {
if (isEmpty()) {
throw new RuntimeException("栈空,没有元素");
}
// 保存出栈(栈顶)节点
Node deleteNode = top;
// 重置top
// 注意:如果重置后top==null,说明当前出栈的节点是栈底节点
top = top.getPrev();
if (top == null) {
// 将bottom也置为null
bottom = null;
} else {
// 否则删除出栈节点
top.setNext(null);
}
return deleteNode.getValue();
}
// 返回栈的大小
public int size() {
if (isEmpty()) {
return 0;
}
int size = 0;
// temp遍历用来辅助遍历
Node temp = bottom;
while (temp != null) {
size++;
temp = temp.getNext();
}
return size;
}
// 遍历栈,应该从top->bottom遍历
public void showStack() {
Node temp = top;
while (temp != null) {
System.out.println(temp.getValue());
temp = temp.getPrev();
}
}
/**
* 声明一个内部类Node,一个Node对象就是一个链表节点
*/
private class Node {
private Node prev; // 前节点指针
private int value; // 存放节点值
private Node next; // 后节点指针
public Node(int value) {
this.value = value;
}
public Node getPrev() {
return prev;
}
public void setPrev(Node prev) {
this.prev = prev;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
@Override
public String toString() {
return "Node{" +
"prev=" + prev +
", value=" + value +
", next=" + next +
'}';
}
}
}
测试
public class LinkedListStackDemo {
public static void main(String[] args) {
// 创建一个栈
LinkedListStack linkedListStack = new LinkedListStack();
Scanner scanner = new Scanner(System.in);
Scanner scanner1 = new Scanner(System.in);
boolean loop = true;
while (loop) {
System.out.println("push(入栈),pop(出栈),show(显示栈),exit(退出程序)");
String key = scanner.nextLine();
switch (key) {
case "push":
System.out.print("请输入一个数:");
int value = scanner1.nextInt();
linkedListStack.push(value);
break;
case "pop":
System.out.println("出栈:" + linkedListStack.pop());
break;
case "show":
System.out.println("显示栈:");
linkedListStack.showStack();
break;
case "exit":
System.out.println("退出程序:");
loop = false;
}
}
}
}
控制台输出
和测试ArrayStack一样