ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2021-09-19 19:37:34  阅读:157  来源: 互联网

标签:17 MyArrayListStack int public 2021 求值 stack rear size


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());
}

标签:17,MyArrayListStack,int,public,2021,求值,stack,rear,size
来源: https://www.cnblogs.com/hujesse4/p/15312420.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有