zoukankan      html  css  js  c++  java
  • 2021/9/17(栈实现+中后缀表达式求值)

    2021/9/17(栈实现+表达式求值)

    栈的应用场景

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

    参考了 https://www.cnblogs.com/hapjin/p/4442729.html

    1 、使用JAVA数组实现顺序栈、

    1、首先总结一下线性表(分为顺序表和链接表,【即顺序存储结构和链式存储结构的区别】)和栈(顺序栈和链接栈)还有队列(顺序队列和链接队列)的JAVA类库中的实现:

    java.util.ArrayList 实现了顺序表,java.util.LinkedList 实现了链接表的功能。

    java.util.ArrayDeque实现了顺序栈和顺序队列(该类中即定义了与栈操作有关的方法,也定义了与队列操作有关的方法)、java.util.LinkedList实现了链接栈和链接队列。

    2、定义了一个Stack接口,指明该栈实现了哪些具体的操作。接口如下

    创建一个基于数组的Stack接口:

    public interface Stack<E> {
        public int length();//返回栈的长度
    
        public E pop();//出栈
    
        public void push(E element);//进栈
    
        public E peek();//访问栈顶元素
    
        public boolean empty();//判断栈是否为空
    
        public void clear();//清空栈
    }
    

    3,在JAVA类库中,java.util.ArrayDeque类实现了顺序栈的功能。ArrayDeque可以实现动态地扩展栈的大小,但是不支持多线程访问。同时,ArrayDeque还实现了顺序队列的功能。

    4,定义了一个Object[] 类型的数组,用来保存顺序栈中的元素。具体实现类MyArrayListStack 如下:

    package stack;
    
    import java.util.Arrays;
    
    public class MyArrayListStack<T> implements Stack<T>{
        private int DEFAULT_SIZE=16;  //定义栈的初始默认长度
        private int capacity;   // 保存栈的长度
        private int size;   //元素个数
        private Object[] elementData;  //保存栈中的元素
    
        public int getCapacity() {
            return capacity;
        }
    
        public void setCapacity(int capacity) {
            this.capacity = capacity;
        }
    
        public MyArrayListStack() {
            capacity = DEFAULT_SIZE;
            elementData = new Object[capacity];
            size = 0;
        }
        // 以指定长度的大小来创建栈
        public MyArrayListStack(int initSize) {
            capacity = 1;
            while (capacity<initSize)
                capacity <<=1;  //将capacity设置成大于initSize的最小2次方
            elementData = new Object[capacity];
        }
    
        @Override
        public int getLength() {
            return this.size;
        }
    
        public T getAt(int idx){
            return elementData(idx);
        }
        @Override
        public T pop() {
            if (empty()){
                throw new IndexOutOfBoundsException("栈空,不能出栈");
            }
            T oldValue =elementData(size-1);
            elementData[--size] = null; ////让垃圾回收器及时回收,避免内存泄露
            return oldValue;
        }
    
        /**
         *  返回运算符的优先级,数字越大优先级就越高
         *  目前 表达式只有+ - * /
         */
        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,char 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;
        }
    
        /**
         * 我用得有一点鸡肋了 ,但ArrayList中有这么用过
         */
        T elementData(int index){
            return (T) elementData[index];
        }
    
        /**
         *     动态扩容 真的太牛逼了!
          */
        public void ensureCapacity(int minCapacity){
            if (minCapacity>capacity){
                while(capacity<minCapacity)
                    capacity <<=1;
            }
            elementData = Arrays.copyOf(elementData,capacity);
        }
        @Override
        public void push(T t) {
            ensureCapacity(size+1);
            elementData[size++] = t;
        }
    
        @Override
        public T peek() {
            if (size==0){
                throw new ArrayIndexOutOfBoundsException("size = 0");
            }
            return elementData(size-1);
        }
    
        @Override
        public boolean empty() {
            return size==0;
        }
        public boolean isNotEmpty(){
            return !empty();
        }
        @Override
        public void clear() {
            for (int i = 0; i < size; i++) {
                elementData[i] = null;
            }
            size = 0;
        }
        public void display() {
            if (size==0){
                System.out.println("[]");
            }
            StringBuilder sb = new StringBuilder("");
            for (int j =size-1;j>=0;j--){
                sb.append(elementData[j].toString()+", ");
            }
            int len = sb.length();
            System.out.println(sb.delete(len - 2, len).append(']').toString());
        }
    

    使用单链表实现栈

    package stack;
    public class MyLinkedListStack<E> implements Stack<E>{
        private int size;
        private Node<E> first;
        private Node<E> rear;
        static class Node<E>{
            E item;
            Node<E> next;
            Node(E x){
                item = x;
            }
        }
    
        public E getFirst() {
            return first.item;
        }
    
        public E getRear() {
            return rear.item;
        }
    
        @Override
        public int getLength() {
            return size;
        }
    
        @Override
        public E pop() {
            if (size==1){
                E val = rear.item;
                first=null;
                rear=null;
                size--;
                return val;
            }
            Node<E> preNode = first;
            E val = rear.item;
            while (preNode.next!=rear){
                preNode = preNode.next;
            }
            preNode.next = null;
            rear = preNode;
            size--;
            return val;
        }
    
        @Override
        public void push(E e) {
            Node<E> node = new Node(e);
            if (size==0){
                first = node;
                rear = node;
                size++;
                return;
            }
            rear.next = node;
            rear = node;
            size++;
        }
    
        @Override
        public E peek() {
            return rear.item;
        }
    
        @Override
        public boolean empty() {
            return size==0;
        }
    
        @Override
        public void clear() {
            while (first!=null){
                pop();
            }
        }
        public void display(){
            Node<E> tmp = first;
            for (int i = 0; i < size; i++) {
                System.out.println(tmp.item);
                tmp = tmp.next;
            }
        }
    }
    
    

    3、使用栈完成表达式的计算思路

    1、通过一个遍历,来遍历我们的表达式

    2、如果是数字,入数字栈

    3、符号入符号栈

    ​ 3.1、如果符号栈为空,直接入

    ​ 3.2、如果符号栈有操作符,就进行比较,如果操作符号优先级<=栈中的操作符,

    ​ 需要从数栈中pop出二个数,再从符号栈pop出一个符号,进行运算。得到结果入

    ​ 数字栈,再入符号栈,如果当前的操作符的优先级大于栈中的操作符,入符号栈。

    4、表达式扫描完毕,就顺序的从数栈和符号栈pop出相应的数和符号,运算。

    5、最后在数栈只有一个数字即结果。

    只能计算简单 ,解决了 5-3-1 问题

    package stack;
    
    public class CalStack {
        public static void main(String[] args) {
            String str = "5-5/5-1"; //中缀表达式
            // 创建二个栈,数栈,一个符号栈
            MyArrayListStack<Integer> numStack = new MyArrayListStack<>();
            MyArrayListStack<Integer> operStack = new MyArrayListStack<>();
            int index = 0; //遍历
            int num1 = 0;
            int num2 = 0;
            int oper = 0;
            int res = 0;
            char ch = ' '; // 将每次扫描得到的ch保存到
            String keepNum = ""; // 保存长的数字
            while (true){
                // 依次得到str的每一个字节
                 ch = str.charAt(index);
                 if(operStack.isOper(ch)){
                     // 判断当前符号栈是不是为空
                     if (operStack.isNotEmpty()){
                         if (operStack.priority(ch)<=operStack.priority(operStack.peek())){
                             if (ch=='-'&& operStack.peek()=='-'){
                                 ch = '+';
                             }
                             num1 = numStack.pop();
                             num2 = numStack.pop();
                             oper = operStack.pop();
                             res = numStack.cal(num1,num2, (char) oper);
                             numStack.push(res);
                             operStack.push((int) ch);
                         }else {
                             operStack.push((int) ch);
                         }
                     }else{
                         operStack.push((int) ch);
                     }
                 }else {
                     keepNum+=ch;
                     // 如果ch已经是str的最后一位,就直接入栈
                     if (index==str.length()-1){
                         numStack.push(Integer.parseInt(keepNum));
                     }else {
                         if(operStack.isOper(str.charAt(index+1))){
                             // 后一位是操作符
                             numStack.push(Integer.parseInt(keepNum));
                             keepNum = "";
                         }
                     }
                     //numStack.push(Integer.parseInt(String.valueOf(ch)));
                 }
                 index+=1;
                 if (index==str.length()){
                     break;
                 }
            }
            while (true){
                if (operStack.empty()){
                    break;
                }
                    num1 = numStack.pop();
                    num2 = numStack.pop();
                    System.out.println(operStack.getLength());
                    oper = operStack.pop();
                    if (oper=='-' && operStack.getLength()!=0 &&  operStack.peek()=='-') {
                        oper ='+';
                    }
                    res = numStack.cal(num1,num2, (char) oper);
                    numStack.push(res);
            }
            System.out.println("表达式为:"+numStack.pop());
        }
    }
    
    

    10进制转换n进制:

    public void conversion10_n(int num,int toNum){
      MyArrayListStack<Integer> stack = new MyArrayListStack<>();
      while (num!=0){
        stack.push(num%toNum);
        num = num/8;
      }
      while (stack.isNotEmpty()){
        System.out.printf("%d",stack.pop());
      }
    }
    

    3、前缀(波兰表达式),中缀(我们使用的),后缀表达式(逆波兰表达式)

    x缀说的是符号的位置,符号在前 前缀

    中缀如何转前缀后缀呢?

    a+b*c-(d+e)

    第一步:按照运算符的优先级对所有的运算单位加括号

    式子变成拉:((a+(bc))-(d+e))
    第二步:转换前缀与后缀表达式
    前缀:把运算符号移动到对应的括号前面
    则变成拉:-( +(a (bc)) +(de))
    把括号去掉:-+a
    bc+de 前缀式子出现
    后缀:把运算符号移动到对应的括号后面
    则变成拉:((a(bc)
    )- (de)+ )-改成:((a(bc)* )+ (de)+ )-
    把括号去掉:abc-de+- 后缀式子出现改成:abc+de+-
    发现没有,前缀式,后缀式是不需要用括号来进行优先级的确定的。

    后缀表达式求解简单式子

    逆波兰表达式 很适合计算机运算。

    从左向右 遇到第一个字符,从栈(这次不分数栈还是符号栈)中pop二个进行计算。结果push进去

    polandExpression("3 4 + 5 * 6 -");
    
    public static void polandExpression(String suffixExpression){
      String[] split = suffixExpression.split(" ");
      List<String> list = Arrays.asList(split);
      MyArrayListStack<String> stack = new MyArrayListStack<>();
      for (String s : list) {
        if (s.matches("\d")){
          stack.push(s);
        }else {
          int num1 = Integer.parseInt(stack.pop());
          int num2 = Integer.parseInt(stack.pop());
          int res = 0;
          try{
            res = stack.cal(num1,num2,s.charAt(0));
          }catch (Exception e){
            e.printStackTrace();
          }
          stack.push("" + res);
        }
      }
      System.out.println("value:  "+stack.pop());
    }
    
  • 相关阅读:
    添加依赖到pom.xml
    关于换了手机后,导致原来连的fiddler抓不到新手机上的包的解决方法
    关于无法使用python执行进入百度页面的代码修改
    安装完jdk配置环境变量
    关于解决工作中的自动化环境搭建的解决方案(序)
    关于微信公众号的测试
    关于发布中报“未能加载文件或程序集“Newtonsoft.Json”或它的某一个依赖项”的问题解决方法
    .Net Native 跨平台尝试
    ASP.NET 5 Beta8 已经发布
    go框架beego Windows 搭建记录和遇到的坑
  • 原文地址:https://www.cnblogs.com/hujesse4/p/15312420.html
Copyright © 2011-2022 走看看