最近准备在android上写一个计算器,发现根本不会写呀,于是就在网上找怎么求表达式的值,最后找到了一个后缀表达式转中缀表达式再计算的方法,也没看懂,正好在学数据结构的栈,发现里面正好有逆波兰表达法,于是就用java写了一个表达式计算。然后又改了个c++版.
首先是准备工作,在计算表达式之前,我们需要知道到底用什么方法才能计算,对于一个算术表达式(中缀表达式),我们需要先转换为逆波兰(后最表达式)后,才能进行计算,不知道的要自行学习了,不然就像我一样找到了代码却看不懂。
首先对于表达式如 “9.2+(3-1.1)*3+10/2” 我用String 保存起来,要想对它进行转化,首先要判断它到底是不是标准的表达式,于是就有:
/**
* 是否为算术表达式
*
* @param str
* @return
*/
private static boolean isExpression(String str) {
int flag = 0;
for (int i = 0; i < str.length() - 1; i++) {
char ch = str.charAt(i);
char chb = str.charAt(i + 1);
if ((!isNum(ch) && i == 0) && ch != '(' || !isNum(chb)
&& (i == str.length() - 2) && chb != ')') {
System.out.println("首尾不是数字---->" + ch + chb);
return false;
}
if ((ch == '.' && !isNum(chb)) || (!isNum(ch) && chb == '.')) {
System.out.println("小数点前后不是数字--->" + ch + chb);
return false;
}
if (isOperator(ch) && !isNum(chb) && chb != '(') {
System.out.println("运算符不是数字--->" + ch + chb);
return false;
}
if (isNum(ch) && !isOperator(chb) && chb != '.' && chb != ')'
&& !isNum(chb)) {
System.out.println("数字后不是运算符--->" + ch + chb);
return false;
}
if (ch == '(') {
flag++;
}
if (chb == ')') {
flag--;
}
}
if (flag != 0) {
System.out.println("括号不匹配--->");
return false;
}
return true;
}
对于标准的表达式就好办些了,但是还是没什么变化,想要把一个字符串算术表达式转化为后缀表达式,我需要先把它分解成数字和运算符,每个数字和运算符都放入String然后装入List里,了代码如下:
/**
* 分解表达式
*
* @param str
* @return
*/
private static List resolveString(String str) {
List list = new ArrayList();
String temp = "";
for (int i = 0; i < str.length(); i++) {
final char ch = str.charAt(i);
if (isNum(ch) || ch == '.') {
char c = str.charAt(i);
temp += c;
} else if (isOperator(ch) || ch == ')') {
if (!temp.equals("")) {
list.add(temp);
}
list.add("" + ch);
temp = "";
} else if (ch == '(') {
list.add("" + ch);
}
if (i == str.length() - 1) {
list.add(temp);
}
}
return list;
}
好了,完成了三分之一,接下来就是重点了,就是把中缀表达式转化为后缀表达式,转换规则是:从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为后缀表达式的一部分,若是符号,则判断其与栈顶符号的优先级,是右括号或优先级低 与栈顶符号(乘除优先加减)则栈顶元素依次出栈并输出,并将当前符号进栈,一直到最终输出后缀表达式为止。当然,我们这里是要后缀表达式的,所以就把输出的内容放到List里了。直接代码
/**
* 中缀表达式转换后缀
*
* @param list
* @return
*/
private static List<String> nifix_to_post(List<String> list) {
Stack<String> stack = new Stack<String>();
List<String> plist = new ArrayList<String>();
for (String str : list) {
if (isDouble(str)) {
plist.add(str);
}
if (isStrOperator(str) && stack.isEmpty()) {
stack.push(str);
} else if (isStrOperator(str) && !stack.isEmpty()) {
String last = stack.lastElement();
if (heightOperator(str, last) || str.equals("(")) {
stack.push(str);
} else if (!heightOperator(str, last) && !str.equals(")")) {
while (!stack.isEmpty() && !stack.lastElement().equals("(")) {
plist.add(stack.pop());
}
stack.push(str);
} else if (str.equals(")")) {
while (!stack.isEmpty()) {
String pop = stack.pop();
if (!pop.equals("(")) {
plist.add(pop);
}
if (pop.equals("(")) {
break;
}
}
}
}
// for(String o : stack){
// System.out.println(o);
// }
}
while (!stack.isEmpty()) {
plist.add(stack.pop());
}
// for (String pl : plist) {
// System.out.println(pl);
// }
return plist;
}
其中有一些自己写的工具方法如下:
/**
* 字符是否为数字
*
* @param ch
* @return
*/
private static boolean isNum(char ch) {
if (ch <= '9' && ch >= '0') {
return true;
} else {
return false;
}
}
/**
* 字符串是否为Double类型
*
* @param s
* @return
*/
private static boolean isDouble(String s) {
try {
Double.valueOf(s);
return true;
} catch (NumberFormatException e) {
return false;
}
}
/**
* 字符是否为运输符
*
* @param ch
* @return
*/
private static boolean isOperator(char ch) {
if (ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '=') {
return true;
} else {
return false;
}
}
/**
* 字符串是否为运算符
*
* @param s
* @return
*/
private static boolean isStrOperator(String s) {
if (s.equals("+") || s.equals("-") || s.equals("*") || s.equals("/")
|| s.equals("(") || s.equals(")")) {
return true;
} else {
return false;
}
}
/**
* 比较运算符优先级
*
* @param o1
* @param o2
* @return
*/
private static boolean heightOperator(String o1, String o2) {
if ((o1.equals("*") || o1.equals("/"))
&& (o2.equals("+") || o2.equals("-")) || o2.equals("(")) {
return true;
} else if ((o1.equals("+") || o1.equals("-"))
&& (o2.equals("*") || o2.equals("/"))) {
return false;
} else if ((o1.equals("*") || o1.equals("/"))
&& ((o2.equals("*") || o2.equals("/")))) {
return true;
} else if ((o1.equals("+") || o1.equals("-"))
&& (o2.equals("+") || o2.equals("-"))) {
return true;
} else {
return false;
}
}
好了,转换完成,终于转换成后缀表达式了,可以计算了,对于后缀表达式的计算,虽然说也用到了栈,但比转换可简单多了,它的规则是:从左到右遍历表达式的每个数字和符号,遇到是数字就进栈,遇到是运算符,就将处于栈顶两个数字出栈,进行运算,运算结果进栈,一直到最终获得结果。来了:
/**
* 计算后缀表达式
*
* @param list
* @return
*/
private static double get_postfis_result(List list) {
Stack stack = new Stack();
for (String str : list) {
if (isDouble(str)) {
stack.push(str);
} else if (isStrOperator(str)) {
double n2 = Double.valueOf(stack.pop());
double n1 = Double.valueOf(stack.pop());
stack.push("" + getCountResult(str, n1, n2));
}
}
return Double.valueOf(stack.pop());
}
最后用主函数测试
public static void main(String[] args) {
String str = "9.2+(3-1.1)*3+10/2";
if (!isExpression(str)) {
System.out.println("ERROR!!");
return;
}
List list = resolveString(str);
list = nifix_to_post(list);
System.out.println(str + "=" + get_postfis_result(list));
}
最后结果是19.9。 对于我这么菜,只能写这么个简单的了,最后我还改了一个c++版的,和这个基本没啥大的差别,下面有源码下载,想看的看一下。代码:
#include
#include
#include
#include
#include
/*
Name: ExpressionResult.cpp
Copyright: null
Author: runing
Date: 26-03-15 15:15
Description: getExpressionResult
*/
using namespace std;
/*
字符是否为数字
*/
bool isNum(char ch)
{
if (ch <= '9' && ch >= '0')
{
return true;
} else
{
return false;
}
}
/*
字符是否为运算符
*/
bool isOperator(char ch)
{
if (ch == '+' || ch == '-' || ch == '*'
|| ch == '/' || ch == '=')
{
return true;
} else
{
return false;
}
}
/*
字符是否为算术表达式
*/
bool isExpression(const string & str)
{
int flag = 0;
for (int i = 0; i < str.length() - 1; i++)
{
const char ch = str[i];
const char chb = str[i + 1];
if ((!isNum(ch) && i == 0) && ch != '(' || !isNum(chb)
&& (i == str.length() - 2) && chb != ')')
{
cout << "首尾不是数字---->" << ch << chb << endl;
return false;
}
if ((ch == '.' && !isNum(chb)) || (!isNum(ch) && chb == '.'))
{
cout << "小数点前后不是数字--->" << ch << chb << endl;
return false;
}
if (isOperator(ch) && !isNum(chb) && chb != '(')
{
cout << "运算符不是数字--->" << ch << chb << endl;
return false;
}
if (isNum(ch) && !isOperator(chb) && chb != '.' && chb != ')'
&& !isNum(chb))
{
cout << "数字后不是运算符--->" << ch << chb << endl;
return false;
}
if (ch == '(')
{
flag++;
}
if (chb == ')')
{
flag--;
}
}
if (flag != 0)
{
cout << "括号不匹配--->" << endl;
return false;
}
return true;
}
/*
字符串转换浮点型
*/
double transformString(const string &str)
{
char char_Str[30];
int i = 0;
for (i = 0; i < str.length(); i++)
{
char_Str[i] = str[i];
}
char_Str[i] = '\0';
return atof(char_Str);
}
/*
浮点型转换字符串
*/
string transformDouble(const double &d1)
{
char char_str[30];
gcvt(d1, 8, char_str);
string str = "";
int i = 0;
for (i = 0; char_str[i] != '\0'; i++)
{
str.append(1, char_str[i]);
}
return str;
}
/*
分解算术表达式字符串
*/
vector<string> & resolveString(vector<string> & s_vector, const string & str)
{
string temp = "";
for (int i = 0; i < str.length(); i++)
{
const char ch = str[i];
if (isNum(ch) || ch == '.')
{
temp += ch;
} else if (isOperator(ch) || ch == ')')
{
if (temp != "")
{
s_vector.push_back(temp);
temp = "";
}
temp.append(1, ch);
s_vector.push_back(temp);
temp = "";
} else if (ch == '(')
{
temp.append(1, ch);
s_vector.push_back(temp);
temp = "";
}
if (i == str.length() - 1)
{
s_vector.push_back(temp);
}
}
return s_vector;
}
/*
字符串是否为数字
*/
bool isDouble(const string &str)
{
if (str == "")
{
return false;
}
if (str[0] == '.' || str[str.length() - 1] == '.')
{
return false;
}
if (str.length() > 1)
{
if (str[0] == '0' && str[1] != '.')
{
return false;
}
}
for (int i = 0; i < str.length(); i++) {
if (!isNum(str[i]) && str[i] != '.')
{
return false;
}
}
return true;
}
/*
字符串是否为运算符
*/
bool isStrOperator(const string & str)
{
if (str == "+" || str == "-" || str == "*" || str == "/"
|| str == "(" || str == ")") {
return true;
} else
{
return false;
}
}
/*
比较运算符优先级
*/
bool heightOperator(const string &o1, const string &o2)
{
if ((o1 == "*" || o1 == "/")
&& (o2 == "+" || o2 == "-") || o2 == "(")
{
return true;
} else if ((o1 == "+" || o1 == "-")
&& (o2 == "*" || o2 == "/"))
{
return false;
} else if ((o1 == "*" || o1 == "/")
&& ((o2 == "*" || o2 == "/")))
{
return true;
} else if ((o1 == "+" || o1 == "-")
&& (o2 == "+" || o2 == "-"))
{
return true;
} else
{
return false;
}
}
/*
中缀表达式转后缀
*/
vector<string> & nifix_to_post(vector<string> & s_vector
, vector<string> & post_v)
{
stack<string> s_stack;
for (int i = 0; i < s_vector.size(); i++)
{
const string str = s_vector[i];
if (isDouble(str))
{
post_v.push_back(str);
} if (isStrOperator(str) && s_stack.empty())
{
s_stack.push(str);
} else if (isStrOperator(str) && !s_stack.empty())
{
string last = s_stack.top();
if (heightOperator(str, last) || str == "(")
{
s_stack.push(str);
} else if (!heightOperator(str, last) && str != ")")
{
while (!s_stack.empty())
{
string pop = s_stack.top();
post_v.push_back(pop);
s_stack.pop();
}
s_stack.push(str);
} else if (str == ")")
{
while (!s_stack.empty())
{
string pop = s_stack.top();
if (pop != "(")
{
post_v.push_back(pop);
s_stack.pop();
} else
{
s_stack.pop();
}
if (pop == "(")
{
break;
}
}
}
}
}
while (!s_stack.empty())
{
post_v.push_back(s_stack.top());
s_stack.pop();
}
// for(int i = 0;i < post_v.size();i++){
// cout<< post_v[i]<< endl;
// }
}
/*
两数算术运算
*/
double getCountResult(string oper, double num1, double num2)
{
if (oper == "+")
{
return num1 + num2;
} else if (oper == "-")
{
return num1 - num2;
} else if (oper == "*")
{
return num1 * num2;
} else if (oper == "/")
{
return num1 / num2;
} else
{
return 0;
}
}
/*
计算后缀表达式
*/
double get_postfis_rearut(vector<string> & post_v)
{
stack<string> e_stack;
string temp = "";
for (int i = 0; i < post_v.size(); i++)
{
string str = post_v[i];
if (isDouble(str))
{
e_stack.push(str);
} else if (isStrOperator(str))
{
double n2 = transformString(e_stack.top());
e_stack.pop();
double n1 = transformString(e_stack.top());
e_stack.pop();
double sum = getCountResult(str, n1, n2);
temp += transformDouble(sum);
e_stack.push(temp);
temp = "";
}
}
return transformString(e_stack.top());
}
int main()
{
string str = "4*((5-2)+5*2.4)";//"9+(3-1)*3+10/2";
vector<string> s_vector;
vector<string> post_v;
if (!isExpression(str))
{
return 0;
}
s_vector = resolveString(s_vector, str);
// for(int i = 0;i < s_vector.size();i++)
// {
// cout<< s_vector[i]<< endl;
// }
nifix_to_post(s_vector, post_v);
cout << str << " = " << get_postfis_rearut(post_v);
return 0;
}