我们小时候应该都玩过那种往弹夹里框框塞子弹的那种玩具手枪,这个子弹的弹夹,我们先塞进去的子弹是最后打出来的,最后塞进去的子弹却是第一个打出来的,这种结构就是栈。
栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。——百度百科
经过上面的介绍,我们来提取一下关键信息。
1、栈是一个先进后出的有序列表
2、栈(stack)是限制线性表中元素的插入和删除只能在线性表的同一端进行的一种特殊线性表。允许插入和删除的一端称为栈顶(Top),另一端为称为栈底(Bottom)。
3、根据栈的定义可知,最先放入栈中元素在栈底,最后放入的元素在栈顶,而删除元素刚好相反,最后放入的元素最先删除,最先放入的元素最后删除
入栈是栈的插入操作,也称进栈、压栈,类似子弹入弹夹。如图所示:
出栈是栈的删除操作,也称弹栈,如同弹夹中的子弹出夹。如图所示:
使用数组来模拟栈思路如下:
1、定义一个top来表示栈顶,初始化为-1.
2、入栈的操作就是,top++;stack[top]=value;
3、出栈就是:临时变量=stack[top];top--;return 临时变量;
代码实现如下:
package datastructure.stack;
import java.util.Scanner;
public class ArrayStackDemo {
public static void main(String[] args) {
//测试一下 ArrayStack 是否正确
// 先创建一个 ArrayStack 对象->表示栈
ArrayStack stack = new ArrayStack(4);
String key = "";
boolean loop = true; //控制是否退出菜单
Scanner scanner = new Scanner(System.in);
while (loop) {
System.out.println("show: 表示显示栈");
System.out.println("exit: 退出程序");
System.out.println("push: 表示添加数据到栈(入栈)");
System.out.println("pop: 表示从栈取出数据(出栈)");
System.out.println("请输入你的选择");
key = scanner.next();
switch (key) {
case "show":
stack.list();
break;
case "push":
System.out.println("请输入一个数");
int value = scanner.nextInt();
stack.push(value);
break;
case "pop":
try {
int res = stack.pop();
System.out.printf("出栈的数据是 %d\n", res);
} catch (Exception e) {
// TODO: handle exception
System.out.println(e.getMessage());
}
break;
case "exit":
scanner.close();
loop = false;
break;
default:
break;
}
}
System.out.println("程序退出~~~");
}
}
class ArrayStack {
private int maxSize; // 栈的大小
private int[] stack; // 数组,数组模拟栈,数据就放在该数组
private int top = -1;// top 表示栈顶,初始化为-1
public ArrayStack(int maxSize) {
this.maxSize = maxSize;
stack=new int[this.maxSize];
}
//栈满
public boolean isFull() {
return top == maxSize - 1;
}
//栈空
public boolean isEmpty() {
return top == -1;
}
//入栈-push
public void push(int value) {
//判断栈是否满
if (isFull()) {
System.out.println("栈满");
return;
}
top++;
stack[top] = value;
}
//出栈-pop
public int pop() {
//判断栈是否空
if (isEmpty()) {
throw new RuntimeException("栈空,没有数据。");
}
int value = stack[top];
top--;
return value;
}
//显示栈的情况[遍历栈], 遍历时,需要从栈顶开始显示数据
public void list() {
//判断栈是否空
if (isEmpty()) {
System.out.println("栈空,没有数据。");
return;
}
System.out.println(top);
//需要从栈顶开始显示数据
for (int i = top; i >= 0; i--) {
System.out.println("stack[" + i + "]=" + stack[i]);
}
}
}
(个人观点,不知是否正确。)还可以使用链表来模拟栈,如果使用前面我们用到的那种方式创建链表,每次新插入的元素都在尾部,这样遍历起来时间复杂度过高,我们可以吧新插入的数据直接放在head的后面,取数据时也只取head.next,遍历时使用辅助变量temp从头遍历到尾,也就是从栈顶遍历到栈底。
思路分析如下:
1、先定义一个头结点,头结点为空,后面添加的元素都添加到head后面。遍历也从head后面开始。判空的条件是head.next==null。
2、入栈的操作就是,新节点.next=head.next;然后head.next=新节点
3、出栈就是:int result=head.next.data; head.next=head.next.next; return result;
完整代码如下:
package datastructure.stack;
import java.util.Scanner;
public class LinkedListStackDemo {
public static void main(String[] args) {
//测试一下 ArrayStack 是否正确
// 先创建一个 ArrayStack 对象->表示栈
LinkedListStack stack=new LinkedListStack();
String key = "";
boolean loop = true; //控制是否退出菜单
Scanner scanner = new Scanner(System.in);
while (loop) {
System.out.println("show: 表示显示栈");
System.out.println("exit: 退出程序");
System.out.println("push: 表示添加数据到栈(入栈)");
System.out.println("pop: 表示从栈取出数据(出栈)");
System.out.println("peek: 表示从栈取出数据(出栈)");
System.out.println("请输入你的选择");
key = scanner.next();
switch (key) {
case "show":
stack.list();
break;
case "push":
System.out.println("请输入一个数");
int value = scanner.nextInt();
stack.push(value);
break;
case "peek":
System.out.println(stack.peek());
break;
case "pop":
try {
int res = stack.pop();
System.out.printf("出栈的数据是 %d\n", res);
} catch (Exception e) {
// TODO: handle exception
System.out.println(e.getMessage());
}
break;
case "exit":
scanner.close();
loop = false;
break;
default:
break;
}
}
System.out.println("程序退出~~~");
}
}
class Node {
int data;
Node next;
}
class LinkedListStack {
Node head=new Node();
//入栈-push
public void push(int value) {
Node xyg = new Node();
xyg.data = value;
xyg.next=head.next;
head.next=xyg;
}
//栈空
public boolean isEmpty() {
if (head.next == null) {
return true;
}
return false;
}
//查看栈首元素
public int peek() {
if (isEmpty()){
throw new RuntimeException("栈空,没有数据。");
}
return head.next.data;
}
//出栈-pop
public int pop() {
//判断栈是否空
if (isEmpty()) {
throw new RuntimeException("栈空,没有数据。");
}
int result=head.next.data;
head.next=head.next.next;
return result;
}
//遍历
public void list(){
if (isEmpty()){
System.out.println("栈空,没有数据。");
}
Node temp=head;
while (temp.next!=null){
System.out.println(temp.next.data);
temp=temp.next;
}
}
}
欢迎批评指正。