厚积薄发打卡Day111:堆栈实践(一)<数组模拟堆栈、链表模拟堆栈、洗牌与发牌的过程>
堆栈知识回顾:
剑指offer打卡Day18 栈的压入、弹出序列(重新学习 Vector 与 Stack)
时隔一年重写博客,用一道简单的例题回顾下所学知识
题目描述
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)
示例
- 输入
- [1,2,3,4,5],[4,3,5,1,2]
- 返回值
- false
具体解题及相关知识回顾都在之前的文章中(剑指offer打卡Day18 栈的压入、弹出序列(重新学习 Vector 与 Stack))感兴趣的读者可自行跳转查看,下面列举下大体思路:
大体思路:
- 将目标数据压入栈中:targetStack ==> || 1< 2< 3 < 4 < 5
- 在压入栈的过程中,用指针遍历待验证的数组 arrayData = > [4,3,5,1,2],若数组元素与压栈元素一致,则说明arrayData中的元素可以通过弹栈实现
代码验证:
public class IsPopOrderTest {
private static boolean IsPopOrder(int[] pushA, int[] popA) {
// 非空判断:
if (pushA.length == 0 || popA.length == 0) {
return false;
}
// 辅助栈,存入栈数据:
Stack<Integer> assistStack = new Stack<>();
// 弹栈验证指针位置
int popTarget = 0;
for (int i : pushA) {
assistStack.push(i);
// 如果栈顶不为空,且栈顶元素等于弹出序列
while (!assistStack.empty() && assistStack.peek() == popA[popTarget]) {
// 出栈
assistStack.pop();
//弹出序列向后一位
popTarget++;
}
}
return assistStack.empty();
}
public static void main(String[] args) {
int[] intA = {1, 2, 3, 4, 5};
int[] intB = {4, 3, 5, 1, 2};
System.out.println(IsPopOrder(intA, intB));
}
}
数组模拟堆栈
请使用数组结构来设计一个Java程序,并使用循环来控制准备压入或者弹出的元素,并仿真堆栈的各种操作,其中必须包括压入(push)与弹出(pop)函数,最后还要输出堆栈内的所有元素
/**
* 用数组模拟堆栈
*/
public class StackByArray {
// 类中的数组
private int[] stack;
// 顶端索引
private int top;
public StackByArray(int stackSize) {
stack = new int[stackSize];
top = 0;
}
// push
public boolean push(int data) {
// 判断是否有位置
if (top > stack.length) {
System.out.println("堆栈已满,无法再压入");
return false;
} else {
stack[top] = data;
top++;
return true;
}
}
// empty
public boolean empty() {
return top == 0;
}
// pop
public int pop() {
if (empty()) {
return -1;
} else {
return stack[--top];
}
}
public static void main(String[] args) {
StackByArray stack = new StackByArray(10);
Random random = new Random();
System.out.println("随机入栈:" );
for (int i = 0; i < 10; i++) {
int i1 = random.nextInt(100);
System.out.print(i1);
System.out.print(" >> ");
stack.push(i1);
}
System.out.println();
System.out.println("弹栈顺序为:");
while (!stack.empty()) {
System.out.print(stack.pop());
System.out.print(" << ");
}
}
}
随机入栈:
95 >> 56 >> 63 >> 18 >> 17 >> 48 >> 45 >> 90 >> 38 >> 10 >>
弹栈顺序为:
10 << 38 << 90 << 45 << 48 << 17 << 18 << 63 << 56 << 95 <<
链表模拟堆栈
请设计一个Java程序,以链表来实现堆栈操作,并使用循环来控制准备压入或者弹出的元素,并仿真堆栈的各种操作,其中必须包括压入(push)与弹出(pop)函数,最后还要输出堆栈内的所有元素
思路模拟
▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁
stack : | <- 入栈
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
↑ ↑
front rear
代码实现:
package stack.stack20230101;
import java.util.Random;
/**
* 链表实现堆栈(类似双指针队列)
*/
public class StackByLink {
// 链表节点的声明
class Node {
int data;
Node next;
public Node(int data) {
this.data = data;
this.next = null;
}
}
// 栈底的指针
public Node front;
// 栈顶的指针
public Node rear;
// 判空:empty
public boolean isEmpty() {
return front == null;
}
// 打印:
public void output_of_Stack() {
Node current = front;
while (current != null) {
System.out.print("[" + current.data + "]");
current = current.next;
}
System.out.println();
}
// 入栈:
public void insert(int data) {
Node node = new Node(data);
if (isEmpty()) {
front = node;
rear = node;
} else {
// todo 重点理解
rear.next = node;
rear = node;
}
}
// 弹栈:
public void pop() {
Node newNode;
if (isEmpty()) {
System.out.println("当前堆栈为空");
return;
}
newNode = front;
if (newNode == rear) {
front = null;
rear = null;
System.out.println("当前堆栈为空");
} else {
while (newNode.next != rear) {
newNode = newNode.next;
}
newNode.next = rear.next;
rear = newNode;
}
}
public static void main(String[] args) {
StackByLink stackByLink = new StackByLink();
Random random = new Random();
System.out.println("入栈:");
for (int i = 0; i < 10; i++) {
int i1 = random.nextInt(100);
System.out.print("<<" + i1 );
stackByLink.insert(i1);
}
System.out.println();
System.out.println("压入堆栈后:");
stackByLink.output_of_Stack();
System.out.println("弹栈:");
while (!stackByLink.isEmpty()) {
stackByLink.pop();
stackByLink.output_of_Stack();
}
}
}
入栈:
<<67<<21<<55<<21<<67<<93<<32<<59<<95<<64
压入堆栈后:
[67][21][55][21][67][93][32][59][95][64]
弹栈:
[67][21][55][21][67][93][32][59][95]
[67][21][55][21][67][93][32][59]
[67][21][55][21][67][93][32]
[67][21][55][21][67][93]
[67][21][55][21][67]
[67][21][55][21]
[67][21][55]
[67][21]
[67]
当前堆栈为空
堆栈模拟洗牌发牌
请设计一个Java程序,用数组仿真扑克牌洗牌及发牌的过程。请用随机数来生成扑克牌后压入堆栈,放满52张牌后开始发牌,使用堆栈的弹出功能给四个人发牌。
package stack.stack20230101;
/**
* 洗牌与发牌全过程:
* 0~12 梅花♣
* 13~25 方块♦
* 26~38 红桃♥
* 39~51 黑桃♠
*/
public class StackShuffle {
static int top = -1;
public static void main(String[] args) {
int[] card = new int[52];
int[] stack = new int[52];
int i, j, k = 0, test;
char ascVal = 5;
int style;
for (i = 0; i < 52; i++) {
card[i] = i;
}
System.out.println("[洗牌中......请稍后!]");
while (k < 30) {
for (i = 0; i < 51; i++) {
for (j = i + 1; j < 52; j++) {
if (((int) (Math.random() * 5)) == 2) {
test = card[i];//洗牌
card[i] = card[j];
card[j] = test;
}
}
}
k++;
}
i = 0;
while (i != 52) {
push(stack, card[i]);
i++;
}
System.out.println("[逆时针发牌]");
System.out.println("[显示各家的牌]\n 东家\t 北家\t 西家\t 南家\t");
System.out.println("========================================");
while (top >= 0) {
style = stack[top] / 13;
switch (style) {
case 0:
ascVal = '♣';
break;
case 1:
ascVal = '♦';
break;
case 2:
ascVal = '♥';
break;
case 3:
ascVal = '♠';
break;
}
System.out.print("[" + ascVal + (stack[top] % 13 + 1) + "]");
System.out.print("\t");
if (top % 4 == 0) {
System.out.println();
}
top--;
}
}
private static void push(int[] stack, int val) {
if (top >= 52 - 1) {
System.out.println("[堆栈已满]");
} else {
top++;
stack[top] = val;
}
}
}
[洗牌中......请稍后!]
[逆时针发牌]
[显示各家的牌]
东家 北家 西家 南家
========================================
[♠12] [♥9] [♦10] [♥6]
[♥5] [♣11] [♣7] [♥13]
[♣12] [♣3] [♠3] [♠8]
[♥4] [♦7] [♥12] [♠13]
[♠6] [♥10] [♦6] [♥8]
[♥11] [♦12] [♦5] [♣1]
[♦4] [♥3] [♣2] [♦8]
[♦13] [♦9] [♠11] [♣4]
[♦1] [♥1] [♠5] [♣8]
[♣10] [♣5] [♠9] [♦3]
[♠10] [♣9] [♠2] [♣6]
[♦11] [♥2] [♣13] [♠4]
[♥7] [♦2] [♠1] [♠7]