实验一:计算器的设计与实现

计算器的设计与实现

实验要求

①能通过设计的按钮控件输入并实现简单算术运算,要求表达式在编辑框中显示,能将运算结果,输出在编辑框内显示;
②能够实现混合运算的求解,算术表达式中包括加、减、乘、除、括号等运算符;并且能够识别括号,优先级正确。
③并保存历史的表达式运算记录。

**技术准备:**图形界面的开发;
**难点:**中缀表达式→后缀表达式,后缀表达式的计算。

实验准备

针对本实验难点,有三种解决方法,下面将一一列举。

方法一:操作符栈、队列实现法

*中缀表达式→后缀表达式
(1)创建后缀表达式队列:postQueue,用于存储逆波兰表达式。
(2)创建操作符栈:opStack,对用户输入的操作符进行处理,用于存储运算符。
(3)从左向右依次读取算术表达式的元素X,分以下情况进行不同的处理:
①如果X是操作数,直接入队;
②如果X是运算符,再分以下情况:
a)如果栈为空,直接入栈。
b)如果X=="(",直接入栈。
c)如果X==")",则将栈里的元素逐个出栈,并入队到后缀表达式中,直到第一个配对的"(“出栈。(注:”(“和”)"都不入队)
③最后将栈中剩余的操作符全部入队。
*计算后缀表达式
(1)创建一个结果栈Res_Stack,用于存放计算的中间过程的值和最终结果。
(2)从左开始向右遍历后缀表达式的元素。
(3)如果取到的元素是操作数,直接入栈Res_Stack,如果是运算符,从栈中弹出2个数进行运算,然后把运算结果入栈。
(4)当遍历完后缀表达式时,计算结果就保存在栈里了。

方法二:双栈算符优先级法

(1)双栈算符优先级法为了实现表达式的求值,需要设置两个栈:
一个是运算符栈OP,用于寄存运算符;
另一个成为操作数栈OPND,用于寄存运算符和运算结果。
(2)自左向右扫描表达式中的每一个字符:
①当扫描到的是运算数,则将其压入栈OPND;
②当扫描到的是运算符时:
如这个运算符比OP栈顶运算符的优先级高,则入栈;
如这个运算符比OP栈顶运算符的优先级低,则从OPND栈中弹出两个运算符,从栈OP中弹出栈顶运算符进行运算,并将运算结果压入栈OPND。
(3)继续处理当前字符,直到遇到结束符而止。

方法三:用二叉树来求解后缀表达式的值

(1)首先准备一个二叉树节点栈s
(2)从左开始向右遍历表达式的元素
(3)新建一个树节点p,值为当前元素的值,如果取到的元素是操作数,直接把p入栈s,如果是运算符,从栈中弹出2个节点,把第一个弹出的节点作为p的右子树,第二个弹出的节点作为p的左子树,然后把p入栈。
(4)当遍历完后缀表达式时,树的根节点就保存在栈里了。

实验过程

本实验我采用Java来实现,由于对Java接触时间不长,对Java的使用还停留在简单的代码编写上。因此,需要提前查阅资料了解Java的监听器和图形用户界面(GUI)的使用方法。
*通过查阅相关资料,了解了一些Java图形用户界面中常用的组件,例如文本框(JTextField)、标签(JLable)等。
还有Java布局管理的相关知识,例如FlowLayout(流布局)、BorderLayout(边界布局)、GridLayout(网络布局)等。
初步了解了GUI相关知识后,便可以着手进行本实验的核心,也就是难点部分的代码设计。
本次实验我用三部分来实现。

Process类

用Porcess类来实现计算器的运算功能,即中缀表达式到后缀表达式的转换,和后缀表达式的计算。
部分重要函数代码段如下:
priority函数和testPriority函数,实现对不同运算符的优先级判断

// 设定优先级
	private static int priority(char a) {
   
		if (a == '*' || a == '/')
			return 2;
		else if (a == '+' || a == '-')
			return 1;
		else
			return 0;
	}

	// 优先级判断
	private  static boolean testPriority(Character c1, char c2) {
   
		if (c1 == null) {
   
			return false;
		}
		return priority(c1) >= priority(c2);
	}

testNumber函数,实现判断是否为数字

// 判断是否为数字
	private static boolean testNumber(char a) {
   
		if (a >= '0' && a <= '9') {
   
			return true;
		}
		return false;
	}

calculation函数,完成计算

private static double calculation(double num1,double num2,String op) {
   
		switch(op) {
   
		case "+":
			return num2+num1;
		case "-":
			return num2-num1;
		case"*":
			return num2*num1;
		case"/":
			return num2/num1;
		default:
			return 0;
		}
	}

convert函数,完成中缀表达式向后缀表达式的转换

//中缀表达式转换为后缀表达式
	public double convert(String expression) {
   
		Stack stack=new Stack();
		StringBuilder sb=new StringBuilder();
		char[] ch = expression.toCharArray();		// 字符串转换为字符数组
		for(int i=0;i<ch.length;++i) {
   
			char c=ch[i];
			if(testNumber(c)) {
   
				sb.append(c);
			}
			
			else if(leftBracket(c)) {
   
				stack.push(c);
			}
			
			else if(rightBracket(c)) {
   
				while(!leftBracket((char)stack.peek())) {
   
					sb.append(stack.pop());
				}
				stack.pop();
			}	
			
			else {
   
				while(stack.size()!=0&&testPriority((Character)stack.peek(),c)) {
   
				sb.append(stack.pop());
				}
				stack.push(c);
			}
		}
		while(stack.size()!=0) {
   
			sb.append(stack.pop());
		}
		return convertResult(sb);
	}

convertResult函数,实现后缀表达式的计算

public double convertResult(StringBuilder sb) {
   
		String str =sb.toString();
		str=str.replace(""," ").trim();
		String s[]=str.split(" ");
		Stack<Double>exp=new Stack<>();
		double result=0;
		for(int i=0;i<s.length;i++) {
   
			if(!testOperator(s[i])) {
   
				exp.push(Double.parseDouble(s[i]));		//若不是运算符,则压栈
			}
			else {
   
				 result=calculation(exp.pop(),exp.pop(),s[i]);	//若为运算符,取出栈顶两数运算
						exp.push(result);
			}
		}
		return result;
	}

Calculation类

Calculation类来完成计算器界面的设计和按键输入
部分重要代码如下

*创建相关按钮

//创建按钮
	String [][] buttons= {
   {
   "7","8"
  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值