- 栈的几个常用的应用场景:
(1)子程序的调用:在跳往某个子程序前,会先将该程序(非跳往的子程序)下条指令的地址存放在堆栈中,直到子程序执行完毕,然后从堆栈中将地址取出,恢复原来程序的执行现场;
(2)处理递归调用:和子程序的调用相似,只是除了要存放下一条指令的地址,还要将参数、区域变量等数据存入堆栈中。
(3)表达式的转换(尤其是“ 中缀表达式 转 后缀表达式 ”)及求值。这个是面试的高频知识点。
(4)其他数据结构的算法,如二叉树的遍历、图的深度优先搜索DFS等。
-
数组栈的定义与基本操作:
定义一个ArrayStack类表示数组栈:
(1)、因为是数组栈, 因此需要定义3个基本属性:
1、栈的最大容量:maxSize ;
2、数组实体: int[ ] stack ;
3、栈顶指针:int top = -1 ;
(2)、判断栈空:top == -1 ; 判断栈满:top == maxSize - 1;
(3)、入栈要先判断栈是否满,出栈要判断栈是否空,这是定义方法的临界条件。
(4)、遍历数组栈,直接采用for循环,且只能从栈顶(top)自顶向下进行定义。
具体代码如下:
//定义一个ArrayStack 表示栈
class ArrayStack {
private int maxSize ; //栈的最大容量
private int[] stack ; //数组模拟栈,数据放在该数组中
private int 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 ;
}
//入栈
public void push(int value){
//入栈前先判断栈是否满
if(isFull()) {
System.out.println("栈满!");
return ;
}
top ++ ;
stack[top] = value ;
}
//出栈
public int pop(){
//出栈前,先判断栈是否空
if(isEmpty()){
//由于必须要返回值,所以用抛出异常来处理
throw new RuntimeException("栈空,没有数据~");
}
int value = stack[top];
top -- ;
return value ;
}
//栈的遍历(只能从栈顶往下遍历)
public void list(){
if(isEmpty()){
System.out.println("没有数据,无法遍历");
return ;
}
for(int i = top ; i >= 0 ; i --){
System.out.printf("stack[%d] = %d\n" , i , stack[i] );
}
}
}
main函数测试代码:
public class ArrayStackDemo {
public static void main(String[] args) {
//测试数组栈是否正确
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) {
System.out.println(e.getMessage());
}
break;
case "exit":
scanner.close();
loop = false ;
break;
}
}
System.out.println("程序退出!");
}
}
-
链栈的定义与基本操作
用链表实现,首先要定义一个节点类SNode:
class SNode{
int no ; //节点编号,是节点排序的依据
SNode next ;
//构造方法
public SNode(int no){
this.no = no ;
}
@Override
//为了输出格式更清楚,在此重写toString方法
public String toString() {
return "SNode [no=" + no + "]";
}
}
然后定义链栈类LinkedStack:
(1)结合栈和链表的性质,需要定义三个基本属性:
1、头节点top,同时充当栈顶指针;
2、栈的容量: int maxSize ;
3、栈中当前元素个数:int count = 0 ;
(2)栈空与栈满的条件用count来定义;
(3)push()与pop()均在链表头部进行:push对应插入节点、pop对应删除节点;
具体代码实现如下:
class LinkedStack{
private SNode top = new SNode(-1);//表示栈顶
private int maxSize = 3 ; //假定栈的最大空间为3
private int count = 0 ; //声明栈的元素个数
//判断栈满
public boolean isFull(){
return count == maxSize ;
}
//判断栈空
public boolean isEmpty(){
return count == 0 ;
}
//入栈操作
public void push(int value){
if(isFull()){
System.out.println("栈满,不能插入栈中");
return ;
}
//push用带头结点的链表使用头插法实现
SNode temp = new SNode(value);
temp.next = top.next;
top.next = temp ;
count ++ ;
}
//出栈操作
public int pop(){
if(isEmpty()){
throw new RuntimeException("栈空,没有数据可出");
}
//pop操作借助top指针实现
SNode temp = top.next ;
top.next = temp.next ;
count -- ;
return temp.no;
}
//显示栈中元素
public void list(){
if(isEmpty()){
System.out.println("没有数据,无法遍历");
return ;
}
SNode temp = top.next;
while(temp!=null){
System.out.println(" " + temp.no);
temp = temp.next ;
}
}
}
main函数及测试代码:
public class LinkedStackDemo {
//链栈的代码实现
public static void main(String[] args) {
//用链表模拟栈
LinkedStack linkedStack = new LinkedStack();
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":
linkedStack.list();
break;
case "push":
System.out.println("请输入一个数:");
int value = scanner.nextInt() ;
linkedStack.push(value);
break;
case "pop":
try {
int res = linkedStack.pop();
System.out.printf("出栈数据为:%d \n",res);
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
case "exit":
scanner.close();
loop = false ;
break;
}
}
System.out.println("程序退出!");
}
}