利用Java实现线性表,完成线性表典型应用--任意表达式计算的设计与实现。
前言
用线性表完成栈的操作,并完成任意表达式的计算,使用接口利用栈的性质完成
一、实验内容
- 编写MyStack类,该类利用线性表(接口MyList, 抽象类MyAbstract及其非抽象子类MyArrayList或MyLinkedList)实现常见数据结构-栈结构的基本操作,包括:
获取栈的大小 public int getSize()
获取栈顶元素 public Object peek()
压栈 public void push(Object o)
出栈 public Object pop()
判断栈是否为空 public boolean isEmpty()
同时提供toString方法,将栈中的所有元素组合为字符串形式返回给调用者。
- 编写表达式计算器类ExpressionCalculator,利用栈结构(MyStack)以及数据结构相关知识,实现任意表达式的四则运算(加、减、乘、除)。要求:表达式从键盘输入,而且可以包括或不包含空格,也可以有圆括号,圆括号可以嵌套;要求利用异常处理相关知识和自定义异常类等,对表达式中可能出现的异常情况(表达式格式错、运算符错、操作数格式错等)进行处理。
- 请完成所有代码的编写和功能测试。代码组织如下所示(仅供参考):
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();
}
}
三、实验结果截图
总结
以上就是关于线性表实现任意计算器的计算的全部内容了,说实话,比我想象的复杂很多,花了相当的时间。