栈,初听这个词还以为是战斗的战呢。
经过学习知道了此“栈“非彼战。栈,与我们小时候玩的那个汉诺塔游戏极其相似,最先放的圆盘最后出,最后放的圆盘最先出,汉诺塔的示意图如下图所示:(此图从百度百科截图过来的)
根据上述的图所示,最上面的那个圆盘要先出去,下面的圆盘才能依次的拿出去,这个就跟我们所学的栈的特性一摸一样,先进后出,后进先出的特性。简而言之,栈的使用便是按照顺序存入的相反的方向取值,栈的实现可以使用数组去实现,也可以使用单链表去实现,这里我使用的是数组来实现的,相比较单链表实现栈,数组实现的栈更利用我们理解。
首先,我们需要初始化一个栈的存储数组,我们创建一个ArrayStack类,在该类中设置了maxStackSize、top以及arrays[]三个基本属性,maxStackSize代表的是栈的总容量;top代表的是栈的栈顶元素下标,top赋值为-1,这个很好理解,当栈是空的时候,数组里面是没有数据的,因此栈顶的值肯定是-1;arrays[]数组就是栈存储数据的结构,利用ArrayStack类的有参构造函数初始化栈的基本数据,代码如下:
class ArrayStack{
//栈大小
private int maxStackSize;
//栈的存储数组
private int[] arrayStack;
//栈顶
private int top;
public ArrayStack(int maxStackSize) {
this.maxStackSize = maxStackSize;
arrayStack = new int[maxStackSize];
top = -1;
}
}
当实现了栈的基本结构之后,我们需要考虑的就是栈的基本方法,比如栈的数据添加,栈的数据获取,栈的数据遍历等等,接下来我就针对添加、获取、以及遍历三个方法展开实现。
在对上述三个方法展开分析和实现之前,我们把最通用的两个方法写好,那就是我们判断栈满以及栈空的方法,isEmpty()和isFull()两个方法。栈满的条件是什么呢,根据我们的分析所得,当top == maxStackSize - 1这个添加满足的时候,就表示当前的栈已经存满了数据,无法再继续存新的数据了;那栈空的条件是什么呢,这个更加容易得到,这个条件在上面介绍top为什么赋值-1的时候便解释了,当top == -1这个条件满足时,就是代表栈空的时候。因此,根据上述的话语,代码实现如下:
//判断栈满
public boolean isFull(){
return top == maxStackSize - 1;
}
//判断栈空
public boolean isEmpty(){
return top == -1;
}
在通用的两个方法实现之后,我开始实现栈的数据添加,这个方法实现的逻辑很简单,从数据传入到该方法中首先先判断栈的空间是否已经存满,如果没有,则arrays[++top] = value,为什么arrays的下标时++top,而不是top,因为top是从-1开始的,而数组的下标是从0开始的,所以使用++top。代码实现如下:
//入栈
public void push(int item){
if (isFull()){
System.out.println("栈满");
return;
}
arrayStack[++top] = item;
}
入栈(栈添加数据)的方法实现之后,我们就需要去拿到栈里面的值,我们就需要编写一个获取数据的方法(出栈);出栈的实现逻辑并不复杂,总体来说,是栈的结构并不是很复杂,甚至可以说很简单,哈哈哈哈,出栈的时候,我们第一步是检测栈是否为空,如果不为空,则返回arrays[top--]即可,top--应该很好理解了,获取完这个数据之后我们便下标左移(从栈的角度看就是下标下移)。代码实现如下:
//出栈
public int pop(){
if (isEmpty()){
throw new RuntimeException("栈空");
}
return arrayStack[top--];
}
最后这个方法都是大家对熟悉的实现方案,遍历,通用for循环,暴力破解的必备神器,也不多说了,就只要记得遍历的时候按照栈的特性遍历,先进后出,后进先出即可,也就是从top开始遍历即可,代码实现如下:
//遍历栈
public void list(){
if (isEmpty()){
System.out.println("栈空");
return;
}
for (int i = top; i >= 0; i--){
System.out.printf("stack[%d]=%d\n", i ,arrayStack[i]);
}
}
栈的常用方法分解讲解完毕,现下的代码是包括测试和栈的所有代码:
import java.util.*;
/**
* 栈
*/
public class ArrayStackDemo {
public static void main(String[] args) {
ArrayStack arrayStack = new ArrayStack(4);
char key;
boolean loop = true;
Scanner scanner = new Scanner(System.in);
while (loop){
System.out.println("s(list):遍历栈");
System.out.println("e(exit):退出程序");
System.out.println("a(push):增加栈数据");
System.out.println("g(pop):获取栈数据");
System.out.println("请输入您的选择:");
key = scanner.next().charAt(0);
switch (key){
case 's':
arrayStack.list();
break;
case 'a':
System.out.println("输入一个数");
int value = scanner.nextInt();
arrayStack.push(value);
break;
case 'g':
try{
System.out.printf("取出的数据是%d\n",arrayStack.pop());
}catch (Exception e){
System.out.println(e.getMessage());
}
break;
case 'e':
scanner.close();
loop = false;
break;
default:
break;
}
}
System.out.println("程序结束!");
}
}
class ArrayStack{
//栈大小
private int maxStackSize;
//栈的存储数组
private int[] arrayStack;
//栈顶
private int top;
public ArrayStack(int maxStackSize) {
this.maxStackSize = maxStackSize;
arrayStack = new int[maxStackSize];
top = -1;
}
//判断栈满
public boolean isFull(){
return top == maxStackSize - 1;
}
//判断栈空
public boolean isEmpty(){
return top == -1;
}
//入栈
public void push(int item){
if (isFull()){
System.out.println("栈满");
return;
}
arrayStack[++top] = item;
}
//出栈
public int pop(){
if (isEmpty()){
throw new RuntimeException("栈空");
}
return arrayStack[top--];
}
//遍历栈
public void list(){
if (isEmpty()){
System.out.println("栈空");
return;
}
for (int i = top; i >= 0; i--){
System.out.printf("stack[%d]=%d\n", i ,arrayStack[i]);
}
}
}
此上便是我对栈的理解和用数组模拟实现,如有不对,烦请大佬指正!
(单链表实现栈,有兴趣的朋友可以尝试着去实现,后续有空的话我会尝试着去实现。)