数据结构和算法(7)之栈

学习数据结构和算法的日常Demo

栈的介绍

在这里插入图片描述
在这里插入图片描述

栈的应用场景

在这里插入图片描述

栈的实现(数组)

在这里插入图片描述
代码如下:

class ArrayStack {
    private int maxSize;    //栈的大小
    private int[] arr;      //数组,存放数据
    private int top = -1;   //表示栈游标,初始-1,放一个数据+1

    public ArrayStack(int maxSize) {
        this.maxSize = maxSize;
        arr = new int[this.maxSize];
    }
     // 栈满
    public boolean isFull() {
        return top == maxSize - 1;
    }

    // 栈空
    public boolean isEmpty() {
        return top == -1;
    }

    // 入栈
    public void push(int data) {
        // 先判断栈是否满
        if (isFull()) {
            System.out.println("栈满!");
            return;
        }
        top++;
        arr[top] = data;
    }

    // 出栈
    public int pop() {
        // 判断栈是否空
        if (isEmpty()) {
            throw new RuntimeException("栈空!");
        }
        int data = arr[top];    // 取出栈上方的元素,top向下移
        top--;
        return data;
    }

    // 遍历栈
    public void print() {
        // 判断栈是否空
        if (isEmpty()) {
            throw new RuntimeException("栈空!");
        }
        // 从栈顶开始
        for (int i = top; i >= 0; i--) {
            System.out.println(arr[i]);
        }
    }
    }

测试:

public class MyStack {

    public static void main(String args[]) {
        ArrayStack stack = new ArrayStack(5);
        Scanner sc = new Scanner(System.in);
        char key = ' ';
        boolean loop = true;
        while (loop) {
            System.out.println("s---->显示栈");
            System.out.println("e---->退出程序");
            System.out.println("a---->添加数据到栈");
            System.out.println("g---->从栈中取数据");
            key = sc.next().charAt(0);      /// 接收一个字符
            switch (key) {
                case 's':
                    stack.print();
                    break;
                case 'a':
                    System.out.println("请输入数据:");
                    int value = sc.nextInt();
                    stack.push(value);

                    break;
                case 'g':
                    try {
                        System.out.println("取出的数据为:" + stack.pop());
                    } catch (Exception e) {
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'e':
                    sc.close();
                    loop = false;   //退出循环
                    System.out.println("程序退出");
                    break;
                default:
                    break;

            }
        }
    }
}

在这里插入图片描述

链表实现栈

代码如下:

// 使用单向链表模拟栈
// 定义Node
class Node {
    public int data;
    public Node next;   // 指向下一个节点

    public Node(int id) {
        this.data = id;
    }

    @Override
    public String toString() {
        return "Node{" +
                "data=" + data +
                '}';
    }
}

// 定义链表栈
class LinkedlistStack {
    private int maxSize;
    private Node head = new Node(0);
    int count = 0;      // 记录插入的节点数量

    public LinkedlistStack(int maxSize) {
        this.maxSize = maxSize;
    }

    // 栈空
    public boolean isEmpty() {
        return count == 0;
    }

    // 栈满
    public boolean isFull() {
        return count == maxSize;
    }

    // 入栈
    public void push(int data) {
        if (isFull()) {
            System.out.println("栈满!");
            return;
        }
        Node node = new Node(data); //创建入栈的节点
        Node temp = head;           //创建辅助指针
        while (temp.next != null) {
            temp = temp.next;
        }
        // 当退出循环时,temp就指向了链表的最后
        temp.next = node;   //将要插入的节点进行尾插
        count++;
        node = null;        //防止内存泄漏
    }

    // 出栈
    public int pop() {
        // 判断栈是否空
        if (isEmpty()) {
            throw new RuntimeException("栈空!");
        }
        Node temp = head;           //创建辅助指针
        while (temp.next.next != null) {
            temp = temp.next;
        }
        // 当退出循环时,temp就指向了链表最后节点的前一个节点
        int data = temp.next.data;      // 利用temp获取栈最后一个节点的数据
        temp.next = temp.next.next;   // 相当于搞了一步删除,利用找到的前一个节点把栈尾节点删掉了
        count--;
        return data;
    }

    // 遍历栈
    public void print() {
        // 判断栈是否空
        if (isEmpty()) {
            throw new RuntimeException("栈空!");
        }
        Node temp = head.next;
        int datas[] = new int[count];       // 保存栈中每个节点的数据
        for (int i = 0; i < count; i++) {
            if (temp != null) {
                datas[i] = temp.data;
            } else {
                return;
            }
            temp = temp.next;
        }
        // 倒序遍历一下该数组,模拟先进后出
        for (int i = datas.length - 1; i >= 0; i--) {
            System.out.println(datas[i]);
        }

    }
}

测试:

public class MyStackByLinkedList {
    public static void main(String args[]) {
        LinkedlistStack stack = new LinkedlistStack(3);
        stack.push(1);
        stack.push(2);
        stack.push(3);
        System.out.println("遍历:");
        stack.print();
        System.out.println("出栈:");
        System.out.println(stack.pop());
        System.out.println(stack.pop());
        System.out.println("遍历:");
        stack.print();
    }
}

在这里插入图片描述

栈的应用
模拟计算器

在这里插入图片描述
在这里插入图片描述
代码实现:

public class Calculator {
    public static void main(String args[]) {

        String exp = "30+2*6-5";
        ArrayStack numStack = new ArrayStack(10);   // 存放数字
        ArrayStack operStack = new ArrayStack(10);      // 存放运算符

        int num1 = 0;
        int num2 = 0;
        int oper = 0;
        int res = 0;
        char ch = ' ';  //将每次扫描到的char保存到ch
        String keep = "";
        for (int i = 0; i < exp.length(); i++) {
            ch = exp.charAt(i);
            // 根据ch的类型做处理
            if (operStack.isOper(ch)) {
                // 如果是运算符,判断当前符号栈是否为空
                if (!operStack.isEmpty()) {
                    // 如果栈不为空,进行比较当前操作符和栈中操作符的优先级
                    // 如果当前的操作符优先级小于栈中操作符
                    if (operStack.priority(ch) <= operStack.priority(operStack.peek())) {
                        num1 = numStack.pop();
                        num2 = numStack.pop();
                        oper = operStack.pop();
                        res = numStack.cal(num1, num2, oper);     // 进行运算
                        numStack.push(res);         // 运算结果入数栈
                        operStack.push(ch);         // 将当前操作符入符号栈
                    } else {
                        // 如果当前的操作符优先级大于栈中操作符,直接入栈
                        operStack.push(ch);
                    }
                } else {
                    // 如果栈为空直接入栈
                    operStack.push(ch);
                }
            } else {
                // 如果是数字,执行工序:
                keep += ch;
                // 如果游标到末尾,则直接将数字入栈
                if (i == exp.length() - 1) {
                    numStack.push(Integer.parseInt(keep));
                } else {
                    // 若是多位数,在处理数时需要往字符串多看一位,若还是数则拼接成多位数,直到下一位是操作符
                    // 判断下一位是操作符还是数
                    if (operStack.isOper(exp.charAt(i + 1))) {
                        // 如果是运算符,该数直接入栈
                        numStack.push(Integer.parseInt(keep));
                        keep = "";
                    }
                }
            }
        }

        // 扫描完毕,顺序从栈中得到相应的数和操作符,运行
        while (true) {
            // 如果符号栈为空,则计算到最后的结果,数栈只有一个数字
            if (operStack.isEmpty()) {
                break;
            }
            num1 = numStack.pop();
            num2 = numStack.pop();
            oper = operStack.pop();
            res = numStack.cal(num1, num2, oper);     // 进行运算
            numStack.push(res);
        }
        System.out.println("运算结果:" + numStack.pop());
//        numStack.print();
//        System.out.println("----------------");
//        operStack.print();
    }
}

//ArrayStack补充方法
/*
    计算器功能
     */
    // 判断运算符优先级
    public int priority(int oper) {
        if (oper == '*' || oper == '/') {
            return 1;
        } else if (oper == '+' || oper == '-') {
            return 0;
        } else {
            return -1;  // 假定运算符只有加减乘除
        }
    }

    // 判断是不是运算符
    public boolean isOper(char val) {
        return val == '+' || val == '-' || val == '*' || val == '/';
    }

    // 计算方法
    public int cal(int num1, int num2, int oper) {
        int res = 0;    // 存放运算结果
        switch (oper) {
            case '+':
                res = num1 + num2;
                break;
            case '-':
                res = num2 - num1;
                break;
            case '*':
                res = num1 * num2;
                break;
            case '/':
                res = num2 / num1;
                break;
            default:
                break;
        }
        return res;
    }

    // 只看栈顶,不弹栈
    public int peek(){
        return arr[top];
    }

测试:
在这里插入图片描述
结果无误!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值