最近看数据结构,看到栈和后缀表达式的地方,于是自己动手用写了一段很简单的实现计算String类型的四则运算的例子。
思路:给一个String类型的算术计算式,求这个String算数式的值。计算String串的值,涉及到一个主要问题:加减乘除及括号的优先级该怎么解决。于是后缀表达式就华丽丽的登场了,它涉及到的数据结构是栈,然后利用后缀表达式计算。
首先中缀转后缀:运算时从左向右开始,1)如果是数字直接输出;2)如果是'(',则直接入栈;3)如果是运算符,先与栈顶元素比较优先级,优先级大于或等于栈顶元素直接入栈,小于栈顶元素优先级则栈顶元素先出栈,之后再与栈顶元素优先级比较,重复3)规则;4)如果是')',则将栈中元素持续出栈,直到'('元素出栈,然后继续按规则1、2、3、4执行。比如9+(3-1)*3-10/2中缀表达式转完后缀表达式为:9 3 1 - 3 * 10 2 / - +
中缀转弯后缀表达式之后就该计算了,将后缀表达式依次入栈,数字直接入栈,运算符不入栈,有运算符时连续弹出2个元素计算后将结果入栈。比如上面的后缀表达式,9先入栈,之后3入栈,之后1入栈,之后为‘-’,则不入栈,先将栈顶的1取出作为被减数(位置要正确,先取出的元素位于运算符右侧),再将3取出作为减数,结果为2,然后将2入栈,按规则一步一步来即可得到结果。下面是我这段时间写的一个小程序,暂时只能运算整数的四则运算,之后有时间了我会慢慢完善。
class D1 implements Serializable {
public static void main(String[] args) {
//这里做测试
D1 d = new D1();
String str = "9+(3-1)*3-10/2";
List<String> list = d.infixToSuffix(str);
Integer num = d.getReslut(list);
System.out.println(num);
}
/**
* 传入转换完毕的后缀表达式,计算
* @param list
* @return
*/
public Integer getReslut(List<String> list){
Integer n1 = null;
Integer n2 = null;
Integer reslut = null;
Deque<Integer> opt = new LinkedList<Integer>();
for(int i=0;i<list.size();i++){
String num = list.get(i);
try {
Integer n = Integer.valueOf(num);
opt.offerFirst(n);
}catch (Exception e){
n2 = opt.pollFirst();
n1 = opt.pollFirst();
if("+".equals(num)){
reslut = n1 + n2;
}else if("-".equals(num)){
reslut = n1 - n2;
}else if("*".equals(num)){
reslut = n1 * n2;
}else if("/".equals(num)){
reslut = n1 / n2;
}
opt.offerFirst(reslut);
}
}
return opt.pollFirst();
}
//9+(3-1)*3-10/2 = 10
// 9 3 1 - 3 * 10 2 / - +
/**
* 中缀表达式转后缀表达式,直接传入算数式
* @param str
* @return
*/
public List<String> infixToSuffix(String str) {
List<String> numlist = getNums(str);
List<String> list = new ArrayList<String>();
Deque<String> deque = new LinkedList<String>();
for (int i = 0; i < numlist.size(); i++) {
// Character c = str.charAt(i);
String num = numlist.get(i);
if("(".equals(num)||"*".equals(num)||"/".equals(num)){
deque.offerFirst(num);
}else if("+".equals(num)||"-".equals(num)){
addAndMul(deque, num, list);
}else if(")".equals(num)){
rightKuo(deque, num, list);
}else{
list.add(num);
}
if (i == numlist.size() - 1) {
while (true) {
String next = deque.pollFirst();
if (null == next) {
break;
}
list.add(next);
}
}
}
return list;
}
private void addAndMul(Deque<String> deque, String c, List<String> list) {
while (true) {
String next = deque.peekFirst();
if (null == next || "+".equals(next) || "-".equals(next) || "(".equals(next)) {
deque.offerFirst(c);
break;
}
list.add(deque.pollFirst());
}
}
private void rightKuo(Deque<String> deque, String c, List<String> list) {
while (true) {
String next = deque.pollFirst();
if ("(" .equals(next)) {
break;
}
list.add(next.toString());
}
}
/**
* 将String类型算数表达式转换为list,将数字与运算符分开
* @param str
* @return
*/
private List<String> getNums(String str) {
String nums = "0123456789";
String opts = "()+-*/";
// String[] ss = new String[str.length()];
List<String> list = new ArrayList<String>();
int j = 0;
for (int i = 0; i < str.length(); i++) {
if (i == 0) {
// ss[j] = str.substring(i, i + 1);
list.add(str.substring(i, i + 1));
} else {
String per = str.substring(i - 1, i);
String now = str.substring(i, i + 1);
if(opts.indexOf(now)>-1 ){
j++;
// ss[j] = now;
list.add(now);
}else if(nums.indexOf(now)>-1){
if(nums.indexOf(per)>-1){
// ss[j]=ss[j]+now;
list.set(j,list.get(j)+now);
}else{
j++;
// ss[j] = now;
list.add(now);
}
}
}
}
return list;
}
}
以上就是这个的应用了,不想自己写栈了,于是就用了java自带的双端队列,只是使用了其中的栈的功能,其中不完善的地方之后再改了,现在就先到这里了。关于栈和后缀表达式建议直接百度,我也是正在学习中,关于这个可能写的不是很清楚。