赞
踩
中缀表达式
逆波兰后缀表达式
待处理问题:(正常人输入情况下!)
思想:
字符串空格在java中可以用字符串自带函数,将字符串空格转化为空字符,完成删除
replaceAll(String , String)
遍历一次,每次遇到数字或者小数点时循环将整个数值制作成字符串就行,其他字符就直接做成字符串
只需要判断每个负号前面的情况就好:
最终放进顺序表或者链表中
//记得导包!
//所有都用static是因为互相使用方便,并且这个方法不需要new一个对象才能使用,通过类名就足够了
public static List<String> transform(String s) {
//1. 去空格
s = s.replaceAll(" ", "");
//2. 存放各元素
List<String> list = new ArrayList();//存储中序表达式
int i = 0;
char c;
do {
if (((c = s.charAt(i)) < 48 || (c = s.charAt(i)) > 57)) {
list.add("" + c);
i++;
} else {
//这里是为了提高效率用了 StringBuilder
//因为本质上字符串相加调用了这个,那么我们多次相加就多次调用,还不如只调用一次!
StringBuilder stringBuilder = new StringBuilder();
while ((i < s.length() && ((c = s.charAt(i)) >= 48 && (c = s.charAt(i)) <= 57))
|| (i < s.length() && (c = s.charAt(i)) == '.')) {
stringBuilder.append(c);
i++;
}
list.add(stringBuilder.toString());
}
} while (i < s.length());
//3. 对特殊负号进行修改
for (int j = 0; j < ls.size(); j++) {
if(list.get(j).equals("-") && (j == 0 || (j > 0 && list.get(j - 1).equals("(")))) {
list.set(j, "-1");
list.add(j + 1, "*");
}
}
return list;
}
面临的问题:
处理:
有一个新的集合存放逆波兰表达式(能在原来的那个平移操作,那真的牛)
当然也可以用switch( String ) 【switch在java中是可以分支字符串的】
public static int getValue(String s) {
if (s.equals("+")) {
return 1;
} else if (s.equals("-")) {
return 1;
} else if (s.equals("*")) {
return 2;
} else if (s.equals("/")) {
return 2;
} else if (s.equals("^")) {
return 2;
} else if (s.equals("%")) {
return 2;
} else {
return 0;
}
}
public class MyStack {
private List<String> list;
private int size;//已有元素个数
public String top;//栈顶元素
//构造方法
public MyStack() {
list = new ArrayList();
size = 0;
top = null;
}
//获取栈已有元素个数
public int size() {
return size;
}
//压栈
public void push(String s) {
list.add(s);
top = s;
size++;
}
//弹出栈顶
public String pop() {
String s = list.get(size - 1);
list.remove(size - 1);
size--;
top = size == 0 ? null : list.get(size - 1);
return s;
}
}
List<String> listStr = transform(s);
遍历表,识别字符串的种类
※ 进行不同操作 【特别重要】
对于数值,直接放入 集合 retList 里面就好。
对于左括号
对于右括号
对于运算符,想象这么一个场景 (#¥@%¥%¥%@) ==》 (()----()----()----()… ) 一个括号式子中实际应该是这个的,
最终将栈中剩余的全部弹入retList中(栈顶弹出,满足思想)
public static List<String> parse(String s) {
List<String> listStr = transform(s);
List<String> retList = new ArrayList<>();
for (String ss : listStr) {
if (ss.matches("^(-?\\d+)(\\.\\d+)?$")) {
retList.add(ss);
} else if (ss.equals("(")) {
ms1.push(ss);
} else if (ss.equals(")")) {
while (!ms1.top.equals("(")) {
retList.add(ms1.pop());
}
ms1.pop();
} else {
while (ms1.size() != 0 && getValue(ms1.top) >= getValue(ss)) {
retList.add(ms1.pop());
}
ms1.push(ss);
}
}
while (ms1.size() != 0) {
retList.add(ms1.pop());
}
return retList;
}
下图以 A + ( B - D )- E / F为例的步骤剖析图:
重点在于如何利用栈!【下面用到的栈是java自带的栈!】
定义计算规则!【先弹出的放在右,后弹出的放在左,因为栈的特性】
public static void cal(Stack<String> stack, String str) {
String str1 = stack.pop();
String str2 = stack.pop();
Double f1 = Double.parseDouble(str1);
Double f2 = Double.parseDouble(str2);
switch (str) {
case "+":
stack.push(f1 + f2 + "");
break;
case "-":
stack.push(f2 - f1 + "");
break;
case "*":
stack.push(f1 * f2 + "");
break;
case "/":
if(f1 == 0) {
throw new ArithmeticException("计算");
}
stack.push(f2 / f1 + "");
break;
case "%" :
if(f1 == 0) {
throw new ArithmeticException("计算");
}
if(((int)(f2 / f1))* f1 == f2) {//确定是否倍数关系的方法
stack.push(0 + "");
}else {
stack.push(f2 % f1 + "");
}
break;
case "^":
stack.push(Math.pow(f2, f1) + "");
break;
}
栈模拟出来那种“套娃”,说到底就是运算“到底”,两个数就通过运算符结合成一个数,直到最后一个数
如下图所示:
public static String calculate(String s) {
List<String> arrayList = reversePolish.parse(s);
Stack<String> stringStack = new Stack<>();
for (int i = 0; i < arrayList.size(); i++) {
String str = arrayList.get(i);
if(str.equals("+") || str.equals("-") || str.equals("*") || str.equals("/") || str.equals("^") || str.equals("%")) {
cal(stringStack, str);//cal为刚才的计算原理
}else {
stringStack.push(str);
}
}
return stringStack.pop();
}
这里埋个伏笔,返回的是字符串,因为我们不仅仅要用到它的值,还要它的字符串。
只需要将字符串转化为double型(用java中String自带的方法)就好了【也可遍历字符串去慢慢构建一个double型也行】
public static void menu() {
System.out.println("***********### 计算器 ###************");
System.out.println(" 1. 获取上一次的值继续运算");
System.out.println(" 2. 重新开始计算");
System.out.println(" 3. 进制转化(只限整数)");
System.out.println(" 4. 获取上一次的n进制序列");
System.out.println(" 5. 查看历史记录");
System.out.println(" 0. 退出");
System.out.println("****************************************");
System.out.print("请选择:> ");
}
String str = "";
Scanner scanner = new Scanner(System.in);
PrevNum prevNum = new PrevNum();
List<String> history = new ArrayList<>();
int input = 0;
do {
menu();
input = scanner.nextInt();
scanner.nextLine();
switch (input) {
case 1:
//区域1
break;
case 2:
//区域2
break;
case 3:
//区域3
break;
case 4 :
//区域4
break;
case 5:
//区域5
break;
case 0:
//区域6
break;
default:
//区域7
break;
}
}while(input != 0);
}
public class 你他妈脑子异常 extends RuntimeException{
public 你他妈脑子异常() {
}
public 你他妈脑子异常(String message) {
super(message);
}
}
为了对一些无脑操作痛击!!!而设计的异常(汉字可以做类名,但是不合理(像触发这个异常的操作者一样),我们应该有正确的写代码风格)
组件1区域1:
System.out.print("请输入:> " + str);
str += scanner.nextLine();
String s1 = str;
str = calculate(str);
System.out.println("=" + Double.parseDouble(str));
history.add(s1 + " = " + Double.parseDouble(str));
获取上一次的值继续运算(那个计算后的字符串被记录下来了,这样就可以追加续写了)
组件2区域2:
System.out.print("请输入:> ");
str = scanner.nextLine();
String s2 = str;
str = calculate(str);
System.out.println("=" + Double.parseDouble(str));
history.add(s2 + " = " + Double.parseDouble(str));
重新开始计算
组件3区域3:
class PrevNum {
String string;
int radix;
public PrevNum() {
}
public PrevNum(String string, int radix) {
this.string = string;
this.radix = radix;
}
public int getValue() {
return Integer.parseInt(string, radix);
}
public void set(String string, int radix) {
this.string = string;
this.radix = radix;
}
@Override
public String toString() {
if (string == null) {
throw new 你他妈脑子异常("明明没有上一个");//自制的异常
}
return "数值为 '" + string + '\'' +
", 进制为 " + radix;
}
}
为记录上一个n进制序列设计的一个类
System.out.print("请输入你接下来输入的数的进制:>");
int r = scanner.nextInt();
scanner.nextLine();
System.out.print("请输入整数对应的" + r + "进制数:> ");
int number = scanner.nextInt(r);
scanner.nextLine();
System.out.print("请输入你要转化为进制[2, 36]:> ");
int radix = scanner.nextInt();//括号内输入radix,代表输入什么进制的
scanner.nextLine();
String string1 = Integer.toString(number, radix);
System.out.println("转化成功:> " + string1);
history.add(Integer.toString(number, r) + " = " + string1 + " (" + r + "->" + radix + ")");
prevNum.set(string1, radix);
进制转化(只限整数)
组件4区域4:
System.out.println(prevNum);
System.out.print("请输入你要转化为进制[2, 36]:> ");
int newRadix = scanner.nextInt();
scanner.nextLine();
String string2 = Integer.toString(prevNum.getValue(), newRadix);
System.out.println("转化成功:> " + string2);
history.add(prevNum.string + " = " + string2 + " (" + prevNum.radix + "->" + newRadix + ")");
prevNum.set(string2, newRadix);
获取上一次的n进制序列
组件5区域5:
System.out.println("================================================");
if(history.size() == 0) {
System.out.println("空");
}else {
for(String s : history) {
System.out.println("声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/275802
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。