day4学习
采用了两种方式实现了栈这个结构
1.数组
2.链表
在链表中对于栈的逆序输出使用了两种方法 第一种方式是对于原来的链表进行逆置输出再重置,第二种方式是直接调用Stack类传入节点类来实现逆序出栈的效果
代码如下:
1数组实现:
package stack;
import java.util.Scanner;
//数组模拟栈
public class ArrayStackDemo {
public static void main(String[] args) {
//测试
//创建一个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 "exit":
scanner.close();
loop = false;
break;
case "push":
System.out.println("请输入一个数");
int value = scanner.nextInt();
Stack.push(value);
break;
case "pop"://因为可能出现抛出异常的情况所以使用try catch捕获异常
try {
int res = Stack.pop();
System.out.printf("出栈的数据是%d \n", res);
} catch (Exception e) {
System.out.println(e.getMessage());
}
break;
default:
break;
}
}
System.out.println("程序退出了");
}
}
//定义一个类表示栈结构
class ArrayStack {
private int maxSize;//定义栈的最大容量
private int[] stack;//数组模拟栈,数据就放在该数组里
private int top = -1;//表示栈顶 初始化为 -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("栈空");//方法被终止且runtime异常可以不需要被捕获
}
int value = stack[top];
top--;
return value;
}
//显示栈的情况,遍历时需要从栈顶开始显示数据
public void list() {
if(isEmpty()) {
System.out.println("栈空");//方法被终止且runtime异常可以不需要被捕获
}
for (int i = top; i >= 0; i--) {
System.out.printf("stack[%d] = %d \n", i,stack[i]);
}
}
}
2.链表实现:
package stack;
import java.util.Stack;
public class LinkedListStackDemo {
public static void main(String[] args) {
// 添加测试节点
Node node1 = new Node(1);
Node node2 = new Node(2);
Node node3 = new Node(3);
Node node4 = new Node(4);
Node node5 = new Node(5);
Node node6 = new Node(6);
// 添加测试链栈 最大长度为5
LinkedListStack linkedListStack = new LinkedListStack(5);
linkedListStack.pushNode(node1);
linkedListStack.pushNode(node2);
linkedListStack.pushNode(node3);
linkedListStack.pushNode(node4);
linkedListStack.pushNode(node5);
// 栈满测试
linkedListStack.pushNode(node6);
// 显示链栈
// linkedListStack.list1(linkedListStack.getHead());
linkedListStack.list2(linkedListStack.getHead());
// 出栈
linkedListStack.popNode();
linkedListStack.popNode();
System.out.println("----------------------");
// 显示链栈
// linkedListStack.list1(linkedListStack.getHead());
linkedListStack.list2(linkedListStack.getHead());
}
}
class LinkedListStack {
private Node head = new Node(0);// 初始化一个头结点
private Node top = head;// 初始情况下栈顶指向head节点
private int maxSize;// 定义栈的最大容量
private int count = 0;// 定义了栈的当前容量
// 构造器 定义了栈的最大容量
public LinkedListStack(int maxSize) {
this.maxSize = maxSize;
}
// 获取头指针
public Node getHead() {
return head;
}
// 获取栈顶节点
public Node getTop() {
return top;
}
// 判断栈满
public boolean isFull() {
return count == maxSize;
}
// 入栈
public void pushNode(Node node) {
if (isFull()) {
System.out.println("栈满");
return;
}
top.next = node;// 如果栈不满则将当前的栈顶节点指向新增节点
top = node;// 新增节点成为新的栈顶节点
count++;// 当前栈容量加1
}
public void popNode() {
if (head.next == null) {
System.out.println("栈空");
return;
}
Node helper = head;// 定义了一个辅助节点
while (true) {
if (helper.next == top) {// 当辅助节点指向栈顶节点的前一个是条件成立
System.out.println("当前栈顶节点是:" + helper.next);
helper.next = null;// 辅助节点指向空 原先的栈顶节点因为没有引用被回收
top = helper;// 当前辅助节点的成为了新的栈顶节点
count--;// 当前栈的容量-1
break;
}
helper = helper.next;
}
}
// //方法一:利用栈这个数据结构,将各个节点压入栈中,然后利用栈的先进后出的特点,实现逆序打印效果
// public void list1(Node head) {
// if(head.next == null) {
// return;//空链表 不能打印
// }
// Stack<Node> stack = new Stack<Node>();
// Node cur = head.next;
// //将链表的所有节点压入栈中
// while(cur != null) {
// stack.push(cur);
// cur = cur.next;
// }
// //将栈中节点打印
// while(stack.size() > 0) {
// System.out.println(stack.pop());
// }
// }
// 方法二:将单链表两次反转 实现逆序打印和恢复的效果
public void reverseList(Node head) {
// 如果为空
if (head.next == null || head.next.next == null) {// 如果链表为空或只有一个节点 那么无需处理
return;
}
Node cur = head.next;
Node next = null;
Node reverseHead = new Node(0);
// 遍历原来的链表 每遍历一个节点就将其取出 并放在新的reversehead 的最前端
while (cur != null) {
next = cur.next;// 先保留cur的下一个节点,因为后面需要使用
cur.next = reverseHead.next;// 将cur的下一个节点指向新的链表的最前端
reverseHead.next = cur;
cur = next; // cur后移
}
// 将head.next指向reverseHead.next
head.next = reverseHead.next;
}
public void list2(Node head) {
if (head.next == null) {
System.out.println("链空");
return;
}
reverseList(head);
Node helper = head.next;
while (helper != null) {
System.out.println(helper);
helper = helper.next;
}
reverseList(head);
}
}
class Node {
public int no;// 编号
public Node next;// 指向下一个节点
public Node(int no) {
this.no = no;
}
// 为了显示方便重写toString方法
public String toString() {
return "Node [no=" + no + "]";
}
}