学习Java数据结构与算法的第七天

栈的一个需求:输入一个表达式722-5+1-5+3-3,实现计算
问题:计算机底层是如何实现?注意不是简单的把算式列出计算,因为我们看这个算式722-5,但是计算机怎么理解这个算式的(对计算机而言,它接受到的就是一个字符串),我们讨论的是这个问题——栈

栈的介绍

  1. 栈的英文为(stack)
  2. 栈是一个先入后出(FILO-First in Last Out)的有序列表
  3. 栈(stack)是限制线性表中元素的插入和删除,只能在线性表的同一端进行的一种特殊线性表,允许插入和删除的一端,为变化的一端,称为栈顶(top),另一端为固定的一端,称为栈底(Bottom)
  4. 根据栈的定义,最先放入栈中元素在栈底,最后放的元素在栈顶,而删除元素刚好相反,最后放入元素最先删除,最先放入的元素最后删除。
  5. 图解栈的出栈(pop)和入栈(push)
    栈的出栈和入栈

栈的应用场景

  1. 子程序的调用:在跳往子程序前,会先将下个指令的地址存到堆栈中,直到子程序执行完成后再将地址取出,以回到原来的程序中
  2. 处理递归的调用:和子程序的调用类似,只是除了储存下一个指令的地址外,也将参数,区域变量等数据存入堆栈中
  3. 表达式的转换(中缀表达式转后缀表达式)与求值(实际解决)
  4. 二叉树的遍历
  5. 图形的深度优先(depth-first)搜索法

栈的快速入门

数组模拟栈的思路分析:

  • 使用数组来模拟栈
  • 定义一个top来表示栈顶
  • 入栈的操作,当有数据加入到栈时,top++;stack[top]=data
  • 出栈的操作,int value = stack[top]; top–; return value;

思路分析图如下:
数组实现栈思路分析图
代码实现如下:

package com.stack;

import java.util.Scanner;

public class ArrayStackDemo {

	public static void main(String[] args) {
		// 测试一下
		ArrayStack stack = new ArrayStack(4); // 创建一个ArrayStack的对象
		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;
			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;
	}

	// 入栈
	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]);
		}
	}
}

运行结果如下:
数组实现栈的运行结果图

练习:使用双链表来实现栈

思路分析:

  • 先定义一个双链表结点类
  • 再定义一个双链表类来管理并实现链表栈的push,pop,list
    注意:采用双链表是为了实现链表的逆序显示来达到栈的逆序显示的目的

代码实现如下:

package com.stack;

import java.util.Scanner;

public class LinkedListStackDemo {

	public static void main(String[] args) {
		// 测试
		SingleLinkedList listStack = new SingleLinkedList();
		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":
				listStack.list();
				break;
			case "push":
				System.out.println("请输入一个数");
				int value = scanner.nextInt();
				Node node = new Node(value);
				listStack.push(node);
				break;
			case "pop":
				try {
					int res = listStack.pop();
					System.out.printf("出栈的数据是%d\n", res);
				} catch (Exception e) {
					System.out.println(e.getMessage());
				}
				break;
			case "exit":
				scanner.close();
				loop = false;
				break;
			default:
				break;
			}
		}
		System.out.println("程序退出");
	}

}

// 定义SingleLinkedList管理我们的单链表栈
class SingleLinkedList {
	// 初始化一个头结点
	private Node head = new Node(0);

	// 返回头结点
	public Node getHead() {
		return head;
	}

	public boolean isEmpty() { // 判断栈是否空
		Node temp = head;
		if (temp.next == null) {
			return true;
		}
		return false;
	}

	// 添加结点入栈
	public void push(Node node) {
		Node temp = head;
		while (true) {
			if (temp.next == null) { // 遍历找到最后一个结点
				break;
			}
			temp = temp.next;
		}
		temp.next = node; // 添加结点入栈
		node.pre = temp;
	}

	// 删除结点出栈
	public int pop() {
		Node temp = head;
		if (isEmpty()) {
			// 栈空抛出异常来处理
			throw new RuntimeException("栈空,无数据");
		}
		while (true) {
			if (temp.next.next == null) { // 找到最后一个结点的前一个结点,删除最后一个结点并输出它
				int x = temp.next.no; // 定义临时辅助变量x用来保存并返回待删除的结点的数字
				temp.next = temp.next.next;
				return x;
			}
			temp = temp.next; // temp向后移动
		}
	}

	// 显示栈的情况
	public void list() {
		Node temp = head.next;
		if (isEmpty()) {
			System.out.println("栈空,无数据");
			return;
		}
		else {
			while (true) {
				if (temp.next == null) {
					break;
				}
				temp = temp.next;
			} //while结束后temp指针指向最后一个结点
			while(true) {
				if (temp == head) {
					break;
				}
				System.out.println(temp);
				temp = temp.pre; //指针向前移动
			}
		}
	}
}

// 定义每个栈的结点
class Node {
	public int no;
	public Node pre; //定义前置指针用来逆序输出
	public Node next;

	// 构造函数
	public Node(int No) {
		this.no = No;
	}

	// 重写toString,显示该方法
	@Override
	public String toString() {
		return "Node [no=" + no + "]";
	}

}

运行结果如下:
双链表实现栈的运行结果图

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值