java实验:用线性表完成任意表达式的计算

利用Java实现线性表,完成线性表典型应用--任意表达式计算的设计与实现。


文章目录

前言

一、实验内容

二、实验代码

三、实验结果截图


前言

用线性表完成栈的操作,并完成任意表达式的计算,使用接口利用栈的性质完成


一、实验内容

  1. 编写MyStack类,该类利用线性表(接口MyList, 抽象类MyAbstract及其非抽象子类MyArrayList或MyLinkedList)实现常见数据结构-栈结构的基本操作,包括:

获取栈的大小         public int getSize()

获取栈顶元素         public Object peek()

压栈                 public void push(Object o)

出栈                 public Object pop()

判断栈是否为空       public boolean isEmpty()

同时提供toString方法,将栈中的所有元素组合为字符串形式返回给调用者。

  1. 编写表达式计算器类ExpressionCalculator,利用栈结构(MyStack)以及数据结构相关知识,实现任意表达式的四则运算(加、减、乘、除)。要求:表达式从键盘输入,而且可以包括或不包含空格,也可以有圆括号,圆括号可以嵌套;要求利用异常处理相关知识和自定义异常类等,对表达式中可能出现的异常情况(表达式格式错、运算符错、操作数格式错等)进行处理。
  2. 请完成所有代码的编写和功能测试。代码组织如下所示(仅供参考):

nuc.ss.mylist_v5(包)

   Expressioncalculating(子包)

ExpressionCaculator.java  (利用栈结构实现任意表达式计算)

ExpressionException.java  (自定义的表达式异常类)

TestExpressionCaculator.java  (测试主类)

   List(子包)

MyAbstractList.java (MyList接口的实现类,MyArrayList和MyLinkedList的抽象父类)

MyArrayList.java  (MyAbstractList的子类,用数组实现线性表)

      MyLinkedList.java (MyAbstractList的子类,用链表实现线性表)  

      MyList.java    (接口,声明了线性表的常用操作)

   stack(子包)

      MyStack.java  (栈结构,利用线性表实现)

二、实验代码

如下:

public interface Mylist {
    /**
     * 将一个新元素添加到线性表的尾部
     * @param e 新元素
     */
    public void add(Object e);

    /**
     * 将一个新元素插入到线性表中索引号为index的位置
     * @param e 新元素
     */
    public void add(int index,Object e);

    /**
     * 清空线性表(回到初始的缺省状态)
     */
    public void clear();

    /**
     * 判断线性表中是否包含指定元素e
     * @param e 元素
     * @return 如果包含,则返回true,否则返回false
     */
    public boolean contains(Object e);

    /**
     * 从线性表中获取索引号为index的元素
     * @param index 元素的索引号
     * @return 元素
     */
    public Object get(int index);

    /**
     * 在线性表中从左往右查找指定元素e
     * @param e 指定元素
     * @return 若找到,返回元素的索引号(如果有多个元素与e匹配,则返回最左边匹配元素的索引号),否则返回-1
     */
    public int indexOf(Object e);

    /**
     * 判断线性表是否为空(即有没有任何元素)
     * @return 如果为空,则返回true 否则返回false
     */
    public boolean isEmpty();

    /**
     * 在线性表中从右往左查找指定元素e
     * @param e 指定元素
     * @return 若找到 返回元素的索引号(如果有多个元素与e匹配 则返回最右边匹配元素的索引号 否则返回-1
     */
    public int lastIndexOf(Object e);

    /**
     * 从线性表中删除指定元素e 若有多个元素匹配,则删除首次匹配的元素
     * @param e 要删除的元素
     * @return 如果删除成功 则返回true 否则返回false
     */
    public boolean remove(Object e);

    /**
     * 从线性表中删除索引号为index的元素
     * @param index 要删除的元素的索引号
     * @return 被删除的元素
     */
    public Object remove(int index);

    /**
     * 使用指定的元素e替换线性表中索引号为index的元素
     * @param index 被替换的元素的索引号
     * @param e 新元素
     * @return 被替换的旧元素
     */
    public Object set(int index,Object e);

    /**
     * 返回当前线性表的长度(元素个数)
     * @return 线性表的长度
     */
    public int size();
}


//MyAbstractList类
public abstract class MyAbstractList implements Mylist{
    protected int size = 0;//线性表的长度
    /**
     * 创建缺省的线性表
     */
    protected MyAbstractList(){}

    /**
     * 使用传入的字符串数组创建线性表
     * @param strings 传入的字符串数组
     */
    protected MyAbstractList(Object[] objects){
        for(int i=0;i<objects.length;i++){
            add(objects[i]);
        }
        size = objects.length;
    }

    /**
     * 将一个新元素添加到线性表的尾部
     * @param e 新元素
     */
    public void add(Object e){
        add(size,e);
    }

    /**
     * 判断线性表是否为空(即有没有任何元素)
     * @return 如果为空 则返回true 否则返回false
     */
    @Override
    public boolean isEmpty(){
        return size ==0;
    }

    /**
     * 返回当前线性表的长度(元素个数)
     * @return 线性表的长度
     */
    public int size(){
        return size;
    }

    /**
     * 从线性表中删除指定元素e,若有多个元素匹配,则删除首次匹配的元素
     * @param e 要删除的元素
     * @return 如果删除成功,则返回true 否则返回false
     */
    public boolean remove(Object e){
        if(indexOf(e)>=0){
            remove(indexOf(e));
            return true;
        } else
            return false;
    }
}
//MyArrayList类
/**
 * 利用数组实现线性表
 * 约定:所有元素类型为Object类
 * @author luyunchi
 * @version plus pro
 */
public class MyArratList extends MyAbstractList {
    public static final int CAPACITY = 100;
    Object[] data = new Object[CAPACITY];

    /**
     * 创建缺省线性表(空表)
     */
    public MyArratList(){}

    /**
     * 使用传入的字符串数组创建线性表
     * @param strings 传入的字符传输组
     */
    public MyArratList(Object[] objects){
        for(int i=0;i<objects.length;i++){
            add(objects[i]);
        }
        //super(strings);
    }

    /**
     * 将一个新元素插入到线性表中索引号为index的位置,<br>
     * 并将插入位置处及其后面的所有元素向右移动一个位置。<br>
     * @param index 插入位置
     * @param e 新元素
     */
    public void add(int index,Object e){
        //向右移动元素
        for(int i=size-1;i>=index;i--){
            data[i+1]= data[i];
        }

        //插入新元素
        data[index] = e;
        //线性表长度加一
        size++;
    }

    /**
     * 从线性表中删除索引号为index的元素,<br>
     * 并将后面的所有元素向左移动一个位置。
     * @param index 要删除的元素的索引号
     * @return 被删除的元素
     */
    public Object remove(int index){
        Object e=data[index];
        //向左移动元素
        for(int i=index;i<size-1;i++){
            data[i]=data[i+1];
        }
        data [size-1]=null;
        //线性表长度减一
        size--;
        return e;
    }

    /**
     *使用指定的元素e替换线性表中索引号为index的元素,<br>
     *并返回被替换的那个旧元素。
     * @param index 被替换的元素的索引号
     * @param e 新元素
     * @return 被替换的旧元素
     */
    public Object set(int index,Object e){
        Object oldE = data[index];
        data[index]=e;
        return oldE;
    }


    /**
     * 重写toString(),返回线性表中的元素。<br>
     * 使用了StringBuilder类(适用单线程),可以换成StringBuffer类(适用多线程)。
     */
    public String toString(){
        StringBuilder result = new StringBuilder("[");
        for(int i=0;i<size;i++){
            result.append(data[i]);
            if(i<size-1)result.append(",");
        }
        return result.toString()+"]";
    }

    /**
     * 清空线性表(回到初始的缺省状态)
     */
    public void clear(){
        data = new Object[CAPACITY];
        size = 0;
    }

    /**
     * 如果线性表中包含元素e,则返回true;否则返回false。
     * @param e 元素
     * @return 如果包含,则返回true;否则返回false。
     */
    public boolean contains(Object e){
        for(int i=0;i<size;i++){
            if(data[i].equals(e)){
                return true;
            }
        }
        return false;
    }

    /**
     * 从线性表中获取索引号为index的元素。
     * @param index 元素的索引号
     * @return 元素
     */
    public Object get(int index){
        return data[index];
    }

    /**
     * 在线性表中从左往右查找指定元素e,若找到,则返回该元素的索引号;<br>
     * 如果有多个元素与e匹配,则返回最左边匹配元素的索引号;<br>
     * 如果找不到,则返回-1。
     * @param e 指定元素
     * @return 若找到,返回元素的索引号;否则返回-1
     */
    public int indexOf(Object e){
        for(int i=0;i<size;i++){
            if(data[i].equals(e)){
                return i;
            }
        }
        return -1;
    }


    /**
     * 在线性表中反向(从右往左)查找指定元素e,若找到,则返回该元素的索引号;<br>
     * 如果有多个元素与e匹配,则返回最右边匹配元素的索引号; <br>
     * 如果找不到,则返回-1。
     * @param e 指定元素
     * @return 若找到,返回元素的索引号;否则返回-1
     */
    public int lastIndexOf(Object e){
        for(int i=size-1;i>=0;i--){
            if(e.equals(data[i]))return i;
        }
        return -1;
    }
}

//expressionCalculator类
import java.util.Scanner;
import java.util.StringTokenizer;

import MyStack.MyStack;

import javax.xml.xpath.XPathExpressionException;

public class ExpressionCalculator {
    private String expression;
    private double result;

    public void work() {
        Scanner sc;
        char continueFlag = 'y';
        while(continueFlag == 'y' || continueFlag == 'Y' ) {
            System.out.println("请输入一个表达式:");
            sc = new Scanner(System.in);
            try {
                expression = sc.nextLine();
                result = computeExpression(expression);
            } catch (Exception e) {
                if (e instanceof ExpressionException)
                    System.out.println("[计算器提示]" + e.getMessage());
                else
                    System.out.println("[计算器提示]表达式非法:" + e.getMessage().substring(18));
                continue;
            }

            System.out.println(expression + " = " + result);

            System.out.println("继续计算吗(y or n)?");
            continueFlag = sc.next().charAt(0);
        }
        System.out.println("谢谢使用!再见!");
    }

    /**计算一个表达式
     * @param expression 要计算的表达式(字符串形式)
     * @return 表达式的计算结果
     * @throws ExpException 抛出表达式异常
     */
    private double computeExpression(String expression) throws ExpressionException {
        // 创建操作数栈
        MyStack operandStack = new MyStack();

        // 创建运算符栈
        MyStack operatorStack = new MyStack();

        // 提取操作数和运算符
        StringTokenizer tokens = new StringTokenizer(expression, "()+-/*", true);

        //步骤1: 扫描tokens
        while(tokens.hasMoreTokens()) {
            String token = tokens.nextToken().trim(); // 提取一个token
            if(token.length() == 0) // 空格
                continue;
            else if(token.charAt(0) == '+' || token.charAt(0) == '-') {
                // 处理运算符栈顶的所有运算符:+, -, *, /
                while(!operatorStack.isEmpty() && (
                        (Character)operatorStack.peek() == '+' ||
                                (Character)operatorStack.peek() == '-' ||
                                (Character)operatorStack.peek() == '*' ||
                                (Character)operatorStack.peek() == '/')) {
                    processAnOperator(operandStack, operatorStack);
                }

                // 运算符+或-进运算符栈
                operatorStack.push(token.charAt(0));
            }
            else if(token.charAt(0) == '*' || token.charAt(0) == '/') {
                // 处理运算符栈顶的所有运算符:*, /
                while(!operatorStack.isEmpty() &&
                        ((Character)operatorStack.peek() == '*' ||
                                (Character)operatorStack.peek() == '/')) {
                    processAnOperator(operandStack, operatorStack);
                }

                // 运算符*或/进运算符栈
                operatorStack.push(token.charAt(0));
            }
            else if(token.trim().charAt(0) == '(') {
                operatorStack.push('('); // '('进栈
            }
            else if(token.trim().charAt(0) == ')') {
                // 处理栈中的所有运算符直到遇到'('
                while((Character)operatorStack.peek() != '(') {
                    processAnOperator(operandStack, operatorStack);
                }

                operatorStack.pop();// '('出栈
            }
            else { // 一个操作数扫描完成
                // 操作数进栈
                operandStack.push(new Double(token));
            }
        }

        //步骤2: 处理运算符栈中所有剩余的运算符
        while(!operatorStack.isEmpty()) {
            processAnOperator(operandStack, operatorStack);
        }

        // 返回结果
        return (Double)operandStack.pop();
    }

    /**
     * 处理一个运算符: 从运算符栈operatorStack中取出一个运算符,然后将其应用到
     * 操作数栈operandStack中的操作数上。
     * @param operandStack 操作数栈
     * @param operatorStack 运算符栈
     * @throws ExpException 抛出表达式异常:被0除
     */
    private void processAnOperator(
            MyStack operandStack, MyStack operatorStack) throws ExpressionException{
        char op = (Character)operatorStack.pop();
        double op2 = (Double)operandStack.pop();
        double op1 = (Double)operandStack.pop();
        if(op == '+')
            operandStack.push(op1 + op2);
        else if(op == '-')
            operandStack.push(op1 - op2);
        else if(op == '*')
            operandStack.push(op1 * op2);
        else if(op == '/') {
            if (op2 == 0)
                throw new ExpressionException("被0除了!!");
            operandStack.push(op1 / op2);
        }

    }

}

//ExpressionException类
public class ExpressionException extends Exception{
    public ExpressionException(){
            super("表达式非法");
    }
            public ExpressionException(String info){
                super(info);
        }

}


//testExpressionCalculator类
public class testExpressionCalculator {

    public static void main(String[] args){
        new ExpressionCalculator().work();
    }
}


//MyStack类
import arraylist.MyArratList;
public class MyStack {
    private MyArratList list= new MyArratList();

    public int getSize(){
        return list.size();
    }
    public Object peek(){
        return list.get(getSize()-1);
    }
    public void push(Object o){
        list.add(o);
    }
    public Object pop(){
        Object o=list.get(getSize()-1);
        list.remove(getSize()-1);
        return o;
    }
    public boolean isEmpty(){
        return list.isEmpty();
    }

    @Override
    public String toString(){
        return "Stack:" + list.toString();
    }

}

三、实验结果截图


总结

以上就是关于线性表实现任意计算器的计算的全部内容了,说实话,比我想象的复杂很多,花了相当的时间。

猜你喜欢

转载自blog.csdn.net/m0_72471315/article/details/127656875