关于逆波兰算法的链接如下逆波兰算法
原理:将一个长表达式转化为2个数字之间的运算。
需求:利用逆波兰算法,推导出一个字母长表达式的单位
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Stack;
import java.util.StringTokenizer;
import java.util.regex.Pattern;
public class ReversePolish4Unit {
private List<String> sList = new ArrayList<String>();// 中缀表达式集合
private List<Object> dList = new ArrayList<Object>();// 后缀表达式集合
private Stack<String> opStack = new Stack<String>();// 操作符栈
private Stack<Object> rStack = new Stack<Object>();// 结果运算栈
private final int level1 = 0;// +-的级别是0
private final int level2 = 1;// */的级别是1
private final int level3 = 3;// 左右括号是3
private static Map<String, List> unit = new HashMap<String, List>() {
private static final long serialVersionUID = 1L;
List<String> oneClass = new ArrayList<String>() {
private static final long serialVersionUID = 1L;
{
add("zhangsan");
}
};
List<String> towClass = new ArrayList<String>() {
private static final long serialVersionUID = 1L;
{
add("lisi");
}
};
List<String> threeClass = new ArrayList<String>() {
private static final long serialVersionUID = 1L;
{
add("wangwu");
}
};
List<String> fourClass = new ArrayList<String>() {
private static final long serialVersionUID = 1L;
{
add("liuliu");
}
};
List<String> fiveClass = new ArrayList<String>() {
private static final long serialVersionUID = 1L;
{
add("luncy");
}
};
List<String> sixClass = new ArrayList<String>() {
private static final long serialVersionUID = 1L;
{
add("dive");
add("lulu");
add("luckly");
}
};
{
put("one", oneClass);
put("tow", towClass);
put("three", threeClass);
put("four", fourClass);
put("five", fiveClass);
put("six", sixClass);
}
};
// 初始化
public ReversePolish4Unit(String input) throws Exception {
// a+b-c*(d+e) 转换为实际值例如:1+2-3*(4+5)
StringTokenizer st = new StringTokenizer(input, "+-*/()", true);
while (st.hasMoreTokens()) {
sList.add(convert2UnitExpress(st.nextToken()));
}
}
// 1.将中缀表达式转换为后缀表达式
private List<Object> convertToReversePolish() throws Exception {
for (String A : sList) {
// 如果是单位,则直接存入dList
if (A.matches("(^\\d+$)|five|four")) {
ArrayList<String> divisorList = new ArrayList<String>();// 除数(分母)
ArrayList<String> dividendList = new ArrayList<String>();// 被除数(分子)
ArrayList<String>[] unitArray = new ArrayList[] { dividendList, divisorList };
dList.add(unitArray);
}
// 如果是操作符
else if (isOperate(A)) {
opstack(A);
} else if (isUnit(A)) {
ArrayList<String> divisorList = new ArrayList<String>();// 除数(分母)
ArrayList<String> dividendList = new ArrayList<String>();// 被除数(分子)
dividendList.add(A);
ArrayList<String>[] unitArray = new ArrayList[] { dividendList, divisorList };
dList.add(unitArray);
} else {
return null;
}
}
// 将栈清空
while (!opStack.empty()) {
dList.add(opStack.pop());
}
return dList;
}
/**
* 对操作符号进行处理
*
* @param dList
* @param op
*/
private void opstack(String op) {
// 如果是空栈,则直接压入
if (opStack.empty()) {
opStack.push(op);
return;
}
// 如果是左括号直接入栈
if ("(".equals(op)) {
opStack.push(op);
return;
}
// 如果op 是右括号则对栈内元素进行出栈操作,直到遇到左括号
if (")".equals(op)) {
String tmp = "";
while (!"(".equals(tmp = opStack.pop())) {
dList.add(tmp);
}
return;
}
// 如果栈顶是左括号,当前操作符号直接入栈
if ("(".equals(opStack.peek())) {
opStack.push(op);
return;
}
// 如果当前操作符的优先级高于栈顶元素,直接入栈
if (comparePriority(op, opStack.peek())) {
opStack.push(op);
return;
}
// 如果当前元素的优先级低于栈顶元素的优先级
if (!comparePriority(op, opStack.peek())) {
// 如果栈顶不是左括号则进行出栈操作
dList.add(opStack.pop());
opstack(op);
}
}
// 判断是不是单位
private boolean isUnit(String num) {
return num.matches("([\u4e00-\u9fa5]+)");
}
// 判断是不是操作符
private boolean isOperate(Object op) {
if (op instanceof String) {
return op.toString().matches("[\\+\\-\\*\\/\\(\\)]");
}
return false;
}
// 判断op1 的优先级 是否大于 op2的优先级
private boolean comparePriority(String op1, String op2) {
return getLevel(op1) > getLevel(op2);
}
// 获得操作符的优先级
private int getLevel(String op) {
if ("+".equals(op) || "-".equals(op)) {
return level1;
}
if ("*".equals(op) || "/".equals(op)) {
return level2;
}
if ("(".equals(op) || ")".equals(op)) {
return level3;
}
return -1;
}
// 2.对后缀表达式进行计算
private Object calculateReversePolish() throws Exception {
for (Object A : dList) {
if (isArray(A))
rStack.push(A);
// 如果是操作符
else if (isOperate(A))
calculate(A.toString());
}
// 栈中最后一个元素就是计算结果
return rStack.pop();
}
private boolean isArray(Object a) {
if (a instanceof ArrayList[]) {
return true;
}
return false;
}
// 取两个操作数进行运算,并将运算结果入栈
private void calculate(String op) throws Exception {
ArrayList<String>[] d2 = (ArrayList<String>[]) rStack.pop(); // 旧操作数
ArrayList<String>[] d1 = (ArrayList<String>[]) rStack.pop(); // 新操作数
if ("*".equals(op)) {
d1[0].addAll(d2[0]);
d1[1].addAll(d2[1]);
} else if ("/".equals(op)) {
d1[0].addAll(d2[1]);
d1[1].addAll(d2[0]);
} else if ("+".equals(op) || "-".equals(op)) {
if ((compareList(d1[0], d2[0]) && compareList(d1[1], d2[1])) || compareList(d2[0], d2[1])) {
} else {
throw new Exception("表达式有误");
}
}
differenceSet(d1);
rStack.push(d1);
}
/**
* 判断两个List是否相同
*
* @param args
* @throws Exception
*/
public synchronized <T extends Comparable<T>> boolean compareList(List<T> a, List<T> b) {
if (a.size() != b.size())
return false;
Collections.sort(a);
Collections.sort(b);
for (int i = 0; i < a.size(); i++) {
if (!a.get(i).equals(b.get(i)))
return false;
}
return true;
}
public static String getUnit(String str) throws Exception {
str = str.replaceAll("SUM\\(([^()+\\-*/]+)\\)", "$1");
ReversePolish4Unit rp = new ReversePolish4Unit(str);
List<Object> list = rp.convertToReversePolish();
if (list == null) {
return "ERROR";
}
return rp.returnUnit((ArrayList<String>[]) rp.calculateReversePolish());
}
/**
* 返回单位
*
* @param result
* @return
* @throws Exception
*/
public String returnUnit(ArrayList<String>[] result) throws Exception {
if (compareList(result[0], result[1])) {
return "%";
} else {
if (result[1].size() < 2 && result[0].size() >= result[1].size()) {
if (result[1].size() == 0 && result[0].size() > 0) {
return result[0].get(0);
} else {
return result[0].get(0) + "/" + result[1].get(0);
}
} else {
return "ERROR";
}
}
}
/**
* 将计算表达式替换成单位表达式
*
* @throws Exception
*/
public String convert2UnitExpress(String str) throws Exception {
if (isOperate(str)) {
return str;
}
for (Entry<String, List> entry : unit.entrySet()) {
if ((entry.getValue()).contains(str)) {
return entry.getKey();
}
}
if (str.matches("\\d+")) {
return "";
}
return "ERROR";
}
/**
* 移除两个List中相同的选项,不删除多余的
*
* @param array
*/
public void differenceSet(ArrayList<String>[] array) {
for (int i = 0; i < array[0].size(); i++) {
for (int j = 0; j < array[1].size(); j++) {
if (array[0].get(i).equals(array[1].get(j))) {
String temp = array[0].get(i);
array[0].remove(temp);
array[1].remove(temp);
break;
}
}
}
}
public static void main(String args[]) throws Exception {
// Pattern pt = Pattern.compile("SUM\\(([^()+\\-*/]*)\\)");
Pattern pt = Pattern.compile("(^\\d+|(\\s&&[^\\f\\n\\r\\t\\v])*$)");
/*
* Matcher mt = pt.matcher(str); while (mt.find()) {
* System.out.println(mt.group(0)); // System.out.println(mt.group(1));
* return; }
*/
System.out.println(getUnit("lulu/lucky-1"));
/*
* if (str.matches("^\\d+|(\\s&&[^\\f\\n\\r\\t\\v])*$")) {
* System.out.println("11"); } else { System.out.println("23"); }
*/
}
}
备注:代码有修改,可能跑不起来,上述代码只提供思路。