栈
1.用栈实现综合计算器(中缀)
1 package Zhan; 2 3 import java.util.Scanner; 4 5 public class ComprehensiveCalculatorDemo { 6 public static void main(String[] args){ 7 MyStack ns=new MyStack(20);//存放数字的栈 8 MyStack os=new MyStack(20);//存放符号的栈 9 int num1=0; 10 int num2=0; 11 int index=0; 12 int res=0; 13 int oper; 14 char c=' '; 15 String multibitNumber=""; 16 System.out.println("输入表达式:"); 17 Scanner s=new Scanner(System.in); 18 String expersion=s.next(); 19 while(true){ 20 c=expersion.substring(index, index+1).charAt(0); 21 if(os.isOperator(c)){ 22 if(os.isEmpty()){ 23 os.push(c); 24 }else{ 25 if(os.priority(c)<os.priority(os.stack[os.top])){ 26 os.push(c); 27 }else{ 28 num1=ns.pop(); 29 num2=ns.pop(); 30 oper=os.pop(); 31 res=os.canculateResult(num1, num2, oper); 32 ns.push(res); 33 os.push(c); 34 35 } 36 } 37 }else{ 38 39 multibitNumber+=c; 40 if(index==expersion.length()-1){ 41 ns.push(Integer.parseInt(multibitNumber)); 42 }else{ 43 if(os.isOperator(expersion.substring(index+1, index+2).charAt(0))){ 44 ns.push(Integer.parseInt(multibitNumber)); 45 multibitNumber=""; 46 } 47 //ns.push(c-48);//进行字符转数字并入数字栈(注意字符"1"和数字"1"的区别!!!) 48 } 49 } 50 index++; 51 if(index>=expersion.length()){ 52 break; 53 } 54 } 55 56 while(true){ 57 if(os.isEmpty()){ 58 break; 59 }else{ 60 num1=ns.pop(); 61 num2=ns.pop(); 62 oper=os.pop(); 63 res=ns.canculateResult(num1, num2, oper); 64 ns.push(res); 65 } 66 67 } 68 int result=ns.pop(); 69 System.out.println(expersion+"="+result); 70 } 71 72 73 74 } 75 76 77 class MyStack{ 78 int maxSize; 79 int stack[]; 80 int top=-1; 81 82 public MyStack(int maxSize) { 83 this.maxSize = maxSize; 84 this.stack=new int[maxSize]; 85 } 86 87 //判断栈是否为空 88 public boolean isEmpty(){ 89 return top==-1; 90 } 91 92 93 94 //判断栈是否已满 95 public boolean isFull(){ 96 return top==maxSize-1; 97 } 98 99 //入栈 100 public void push(int data){ 101 if (isFull()){ 102 System.out.println("栈已满!!!"); 103 }else{ 104 top++; 105 stack[top]=data; 106 } 107 } 108 109 110 111 //出栈 112 public int pop(){ 113 if(isEmpty()){ 114 throw new RuntimeException("栈空!!!"); 115 }else{ 116 int temp=stack[top]; 117 top--; 118 return temp; 119 } 120 } 121 122 123 124 125 126 127 //显示栈内数据 128 public void show(){ 129 if(isEmpty()){ 130 throw new RuntimeException("栈空!!!"); 131 }else{ 132 for(int i=top;i>-1;i--){ 133 System.out.println("stack["+i+"]----->"+stack[i]); 134 } 135 } 136 } 137 138 139 140 141 142 143 //设定运算符号的优先级,优先级越高,所对应的数字越小,从1开始 144 public int priority(int operator){ 145 if(operator=='*'||operator=='/'){ 146 return 0; 147 }else if(operator=='+'||operator=='-'){ 148 return 1; 149 }else{ 150 return -1; 151 } 152 } 153 154 155 156 157 158 //判断是否为运算符 159 public boolean isOperator(int a){ 160 if(a=='*'||a=='/'||a=='+'||a=='-'){ 161 return true; 162 }else{ 163 return false; 164 } 165 } 166 167 168 169 170 171 //加、减、乘、除计算 172 public int canculateResult(int num1,int num2,int operator){ 173 int result=0; 174 switch(operator){ 175 case'*': 176 result=num2*num1; 177 break; 178 case'/': 179 result=num2/num1; 180 break; 181 case'+': 182 result=num2+num1; 183 break; 184 case'-': 185 result=num2-num1; 186 break; 187 default: 188 break; 189 } 190 191 return result; 192 193 } 194 195 }
结果:



存在问题:
最后一位数前的运算符号,将“+”当作"-",把“-”当作"+"
---------------------------------------------------------------------------------


这样反而没错
------------------------------------------------------------------------------------

打印每一步运算结果,可以发现,问题出现在最后while循环的计算里面,计算是从栈顶开始的,表现在运算式中是从后向前计算,这时,每一个运算符号后面的式子会先计算,相当于加了(),如果这个运算符号是+,那么后面加不加()的没什么影响,如果这个运算符号是-。那么后面加上()的话就会导致计算出的结果和原式不同。
修改:添加以下代码

完整代码:
1 package Zhan; 2 3 import java.util.Scanner; 4 5 public class ComprehensiveCalculatorDemo2 { 6 7 public static void main(String[] args){ 8 9 MyStack2 ns=new MyStack2(20); 10 MyStack2 os=new MyStack2(20); 11 System.out.println("输入表达式:"); 12 Scanner scanner=new Scanner(System.in); 13 String expersion=scanner.next(); 14 int num1=0; 15 int num2=0; 16 int res=0; 17 int oper; 18 int index=0; 19 char c=' '; 20 String multibitNumber=""; 21 22 //扫描表达式 23 while(true){ 24 c=expersion.substring(index, index+1).charAt(0);//一位一位截取字符串,并将截取后的内容准换为char类型 25 if(os.isOperator(c)){ 26 if(os.isEmpty()){ 27 os.push(c); 28 }else{ 29 if(os.priority(c)<=os.priority(os.stack[os.top])){ 30 num1=ns.pop(); 31 num2=ns.pop(); 32 oper=os.pop(); 33 res=os.canculateResult(num1, num2, oper); 34 ns.push(res); 35 os.push(c); 36 }else{ 37 os.push(c); 38 } 39 } 40 }else{ 41 multibitNumber+=c; 42 if(index>=expersion.length()-1){ 43 ns.push(Integer.parseInt(multibitNumber)); 44 }else{ 45 if(os.isOperator(expersion.subSequence(index+1, index+2).charAt(0))){//判断当前数字后面是否有数字,若有则进行拼接,再入栈,若没有则直接入栈 46 ns.push(Integer.parseInt(multibitNumber)); 47 multibitNumber=""; 48 } 49 } 50 } 51 index++; 52 if(index==expersion.length()){ 53 break; 54 } 55 56 } 57 58 59 //需要修改,使数栈和符号栈中的元素倒排 60 /* 61 while(true){ 62 if(os.isEmpty()){ 63 break; 64 }else{ 65 num1=ns.pop(); 66 num2=ns.pop(); 67 oper=os.pop(); 68 res=ns.canculateResult(num1, num2, oper); 69 ns.push(res); 70 } 71 72 } 73 74 */ 75 int a; 76 int b; 77 MyStack2 ns1=new MyStack2(20);//定义一个新的数栈,将原数栈中的元素压入栈,实现元素倒排 78 MyStack2 os1=new MyStack2(20);//定义一个新的符号栈,将原符号栈中的元素压入栈,实现元素倒排 79 80 while(ns.top!=-1){ 81 a=ns.pop(); 82 ns1.push(a); 83 84 } 85 86 87 while(os.top!=-1){ 88 b=os.pop(); 89 os1.push(b); 90 } 91 92 //对新的数栈和符号栈进行之前的操作 93 while(true){ 94 if(os1.isEmpty()){ 95 break; 96 }else{ 97 num1=ns1.pop(); 98 num2=ns1.pop(); 99 oper=os1.pop(); 100 res=ns1.canculateResult(num2, num1, oper);//注意参数顺序,与上面的canculateResult()方法中的参数顺序不同!!! 101 ns1.push(res); 102 } 103 } 104 105 int result=ns1.pop(); 106 System.out.println(expersion+"="+result); 107 108 109 110 } 111 } 112 113 114 115 116 class MyStack2{ 117 int maxSize; 118 int stack[]; 119 int top=-1; 120 121 public MyStack2(int maxSize) { 122 this.maxSize = maxSize; 123 this.stack=new int[maxSize]; 124 } 125 126 //判断栈是否为空 127 public boolean isEmpty(){ 128 return top==-1; 129 } 130 131 132 133 //判断栈是否已满 134 public boolean isFull(){ 135 return top==maxSize-1; 136 } 137 138 //入栈 139 public void push(int data){ 140 if (isFull()){ 141 System.out.println("栈已满!!!"); 142 }else{ 143 top++; 144 stack[top]=data; 145 } 146 } 147 148 149 150 //出栈 151 public int pop(){ 152 if(isEmpty()){ 153 throw new RuntimeException("栈空!!!"); 154 }else{ 155 int temp=stack[top]; 156 top--; 157 return temp; 158 } 159 } 160 161 162 163 164 165 166 //显示栈内数据 167 public void show(){ 168 if(isEmpty()){ 169 throw new RuntimeException("栈空!!!"); 170 }else{ 171 for(int i=top;i>-1;i--){ 172 System.out.println("stack["+i+"]----->"+stack[i]); 173 } 174 } 175 } 176 177 178 179 180 181 182 //设定运算符号的优先级,优先级越高,所对应的数字越大,从0开始 183 public int priority(int operator){ 184 if(operator=='*'||operator=='/'){ 185 return 1; 186 }else if(operator=='+'||operator=='-'){ 187 return 0; 188 }else{ 189 return -1; 190 } 191 } 192 193 194 195 196 197 //判断是否为运算符 198 public boolean isOperator(int oper){ 199 if(oper=='*'||oper=='/'||oper=='+'||oper=='-'){ 200 return true; 201 }else{ 202 return false; 203 } 204 } 205 206 207 208 209 210 //加、减、乘、除计算 211 public int canculateResult(int num1,int num2,int operator){ 212 int result=0; 213 switch(operator){ 214 case'*': 215 result=num2*num1; 216 break; 217 case'/': 218 result=num2/num1; 219 break; 220 case'+': 221 result=num2+num1; 222 break; 223 case'-': 224 result=num2-num1; 225 break; 226 default: 227 break; 228 } 229 return result; 230 231 } 232 233 234 235 }
运行结果:

正确!!!
2.中缀表达式转后缀表达式
2.1步骤

2.2将String类型的中缀表达式分割,并将分割后的元素存入到链表中
1 public static List<String>StringToList(String ex){ 2 List<String>ls=new ArrayList<String>(); 3 int i=0; 4 String st; 5 while(i<ex.length()){ 6 if((ex.charAt(i)<48)||(ex.charAt(i)>57)){//如果是符号,则直接添加 7 ls.add(ex.charAt(i)+""); 8 i++; 9 }else{ 10 st=""; 11 //如果是数字,则需要考虑是否为多位数 12 while((ex.charAt(i)>47&&ex.charAt(i)<58)&&(i<ex.length())){ 13 st=st+ex.charAt(i); 14 i++; 15 } 16 17 ls.add(st); 18 } 19 } 20 return ls; 21 }
运行:
(1)输入:1+
结果:

(2)输入:1+1
结果:

出现越界报错!!!
问题出在:当i已经越界时,还要执行ex.charAt(i)>47&&ex.charAt(i)<58这一步判断,而此时i已经越界,无法取到ex.charAt(i)的值,所以会报错

修改:调整一下判断顺序即可,先进性越界判定,再进行值的范围判定
![]()
2.3中缀转后缀并计算结果的完整代码
1 package Zhan; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 import java.util.Scanner; 6 import java.util.Stack; 7 8 /* 9 * 将中缀表达式转换为后缀表达式,并计算结果 10 * 步骤: 11 * 1.遇到数字,将其压入s2; 12 * 2.遇到括号: 13 * (1)若为(,则压入s1栈; 14 * (2)否则若为),则在s1中寻找(,将()中的元素全部从s1中弹出,并一次压入s2栈 15 * 3.遇到运算符 16 * (1)若s1栈为空或者s1栈顶是(,则入s1栈; 17 * (2)否则,若此符号的优先级大于s1栈顶符号的优先级,则将此符号压入s1栈; 18 * (3)否则,如此符号的优先级小于等于s1栈顶符号优先级,则将此时s1栈顶的符号弹出并压入s2栈,然后再回到第(1)步进行判断,并执行相应的程序,一直循环,直到s1为空为止 19 */ 20 public class CalculateDemo { 21 public static void main(String[] args){ 22 while(true){ 23 System.out.println("输入表达式:"); 24 Scanner scanner=new Scanner(System.in); 25 String ex=scanner.next(); 26 27 List<String>getList=StringToList(ex); 28 29 /* 30 for(String data:getList){ 31 System.out.println(data); 32 } 33 */ 34 Stack<String> s1=new Stack<String>(); 35 Stack<String> s2=new Stack<String>(); 36 //List<String>s2=new ArrayList<String>(); 37 38 /* 39 * 遍历存储中缀表达式的链表 40 */ 41 for(String data:getList){ 42 if(data.matches("\\d+")){ //如果是数字,则压入s2栈 43 s2.push(data); 44 //s2.add(data); 45 46 //如果是括号 47 }else if(data=="("){ 48 s1.push(data);//左括号入s1栈 49 }else if(data==")"){//右括号则在s1栈中找左括号,将括号中的全部元素从s1栈中弹出,并一次压入s2栈,执行完后,s1栈中将不含括号 50 while(s1.peek()!="("){ 51 s2.push(s1.pop()); 52 //s2.add(s1.pop()); 53 } 54 s1.pop();//弹掉s1顶部的“(” 55 }else{ 56 //既不是数字,也不是括号,则为符号 57 while(s1.size()>=0){ 58 if(s1.isEmpty()||s1.peek()=="("){ 59 s1.push(data); 60 break; 61 }else if(getPriority(data)>getPriority(s1.peek())){ 62 s1.push(data); 63 break; 64 }else{ 65 s2.push(s1.pop()); 66 //s2.add(s1.pop()); 67 } 68 } 69 } 70 71 } 72 73 //将s1中剩余的元素全部一次压入s2中 74 while(s1.size()>0){ 75 s2.push(s1.pop()); 76 } 77 78 79 /* 80 * s2的逆序为原中缀表达式的逆序形式,新建一个链表存储后缀表达式 81 */ 82 //1.首先新建一个栈,完成对s2的逆序 83 Stack<String> temp=new Stack<String>(); 84 while(s2.size()>0){ 85 temp.push(s2.pop()); 86 } 87 88 //2.用一个链表,将temp中的元素弹出并保存 89 List<String>houZhui=new ArrayList<String>(); 90 91 while(temp.size()>0){ 92 houZhui.add(temp.pop()); 93 } 94 95 96 97 for(String ele:houZhui){ 98 System.out.print(ele+","); 99 } 100 System.out.println(); 101 102 /* 103 Stack<String> stack=new Stack<String>();//新建一个栈来进行运算 104 105 106 //此时houZhui链表中保存的为原中缀表达式的后缀表现形式,只需按照后缀表达式计算的方法来计算即可 107 108 for(String item:houZhui){ 109 //使用正则表达式匹配多位数 110 if(item.matches("\\d+")){ 111 stack.push(item);//如果取出的是数,则入栈 112 }else{//如果取出的是运算符,则弹出两个数进行运算,并将运算结果入栈 113 int num2=Integer.parseInt(stack.pop()); 114 int num1=Integer.parseInt(stack.pop()); 115 int res=0; 116 if(item.equals("+")){ 117 res=num1+num2; 118 }else if(item.equals("-")){ 119 res=num1-num2; 120 }else if(item.equals("*")){ 121 res=num1*num2; 122 }else if(item.equals("/")){ 123 res=num1/num2; 124 }else{ 125 throw new RuntimeException("运算符有误!!!"); 126 } 127 stack.push(res+""); 128 } 129 } 130 131 132 int result=Integer.parseInt(stack.pop()); 133 System.out.println(ex+"="+result); 134 135 */ 136 137 138 } 139 140 } 141 142 143 144 145 146 147 //使用链表存储分割好后的中缀表达式 148 public static List<String>StringToList(String ex){ 149 List<String>ls=new ArrayList<String>(); 150 int i=0; 151 String st; 152 while(i<ex.length()){ 153 if(ex.charAt(i)<48||ex.charAt(i)>57){//如果是符号,则直接添加 154 ls.add(ex.charAt(i)+""); 155 i++; 156 }else{ 157 st=""; 158 //如果是数字,则需要考虑是否为多位数 159 while((i<ex.length())&&(ex.charAt(i)>47&&ex.charAt(i)<58)){ 160 st=st+ex.charAt(i); 161 i++; 162 } 163 ls.add(st); 164 } 165 } 166 return ls; 167 } 168 169 public static int getPriority(String oper){ 170 if(oper=="*"||oper=="/"){ 171 return 1; 172 }else if(oper=="+"||oper=="-"){ 173 return 0; 174 }else{ 175 return -1; 176 } 177 } 178 179 }
运行结果:

分析:有问题,括号没有除掉
原因:在进行括号判断时,使用了“==”进行判断,导致判断出错,本应该判断为是括号,结果判断的不是括号,导致括号那部分的程序没有执行
修改:将“==”改为.equals()判断方法

修改后的完整代码:
1 package Zhan; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 import java.util.Scanner; 6 import java.util.Stack; 7 8 /* 9 * 将中缀表达式转换为后缀表达式,并计算结果 10 * 步骤: 11 * 1.遇到数字,将其压入s2; 12 * 2.遇到括号: 13 * (1)若为(,则压入s1栈; 14 * (2)否则若为),则在s1中寻找(,将()中的元素全部从s1中弹出,并一次压入s2栈 15 * 3.遇到运算符 16 * (1)若s1栈为空或者s1栈顶是(,则入s1栈; 17 * (2)否则,若此符号的优先级大于s1栈顶符号的优先级,则将此符号压入s1栈; 18 * (3)否则,如此符号的优先级小于等于s1栈顶符号优先级,则将此时s1栈顶的符号弹出并压入s2栈,然后再回到第(1)步进行判断,并执行相应的程序,一直循环,直到s1为空为止 19 */ 20 public class CalculateDemo { 21 public static void main(String[] args){ 22 while(true){ 23 System.out.println("输入表达式:"); 24 Scanner scanner=new Scanner(System.in); 25 String ex=scanner.next(); 26 27 List<String>getList=StringToList(ex); 28 29 30 /* 31 System.out.println("---------------------"); 32 for(String data:getList){ 33 System.out.print(data+" "); 34 } 35 System.out.println(); 36 System.out.println("---------------------"); 37 */ 38 39 40 Stack<String> s1=new Stack<String>(); 41 Stack<String> s2=new Stack<String>(); 42 43 44 /* 45 * 遍历存储中缀表达式的链表 46 */ 47 for(String data:getList){ 48 if(data.matches("\\d+")){ //如果是数字,则压入s2栈 49 s2.push(data); 50 51 //如果是括号 52 }else if(data.equals("(")){ 53 s1.push(data);//左括号入s1栈 54 }else if(data.equals(")")){//右括号则在s1栈中找左括号,将括号中的全部元素从s1栈中弹出,并依次压入s2栈,执行完后,s1栈中将不含括号 55 while(true){ 56 if((s1.peek()).equals("(")){ 57 break; 58 }else{ 59 s2.push(s1.pop()); 60 } 61 } 62 s1.pop();//弹掉s1顶部的“(” 63 }else{ 64 65 //既不是数字,也不是括号,则为符号 66 while(s1.size()>=0){ 67 if(s1.isEmpty()||s1.peek().equals("(")){ 68 s1.push(data); 69 break; 70 }else if(getPriority(data)>getPriority(s1.peek())){ 71 s1.push(data); 72 break; 73 }else{ 74 s2.push(s1.pop()); 75 } 76 } 77 } 78 79 } 80 81 //将s1中剩余的元素全部一次压入s2中 82 while(s1.size()>0){ 83 s2.push(s1.pop()); 84 } 85 86 87 /* 88 * s2的逆序为原中缀表达式的逆序形式,新建一个链表存储后缀表达式 89 */ 90 //1.首先新建一个栈,完成对s2的逆序 91 Stack<String> temp=new Stack<String>(); 92 while(s2.size()>0){ 93 temp.push(s2.pop()); 94 } 95 96 //2.用一个链表,将temp中的元素弹出并保存 97 List<String>houZhui=new ArrayList<String>(); 98 99 while(temp.size()>0){ 100 houZhui.add(temp.pop()); 101 } 102 103 104 /* 105 for(String ele:houZhui){ 106 System.out.print(ele+","); 107 } 108 System.out.println(); 109 */ 110 111 112 Stack<String> stack=new Stack<String>();//新建一个栈来进行运算 113 114 115 //此时houZhui链表中保存的为原中缀表达式的后缀表现形式,只需按照后缀表达式计算的方法来计算即可 116 117 for(String item:houZhui){ 118 //使用正则表达式匹配多位数 119 if(item.matches("\\d+")){ 120 stack.push(item);//如果取出的是数,则入栈 121 }else{//如果取出的是运算符,则弹出两个数进行运算,并将运算结果入栈 122 int num2=Integer.parseInt(stack.pop()); 123 int num1=Integer.parseInt(stack.pop()); 124 int res=0; 125 if(item.equals("+")){ 126 res=num1+num2; 127 }else if(item.equals("-")){ 128 res=num1-num2; 129 }else if(item.equals("*")){ 130 res=num1*num2; 131 }else if(item.equals("/")){ 132 res=num1/num2; 133 }else{ 134 throw new RuntimeException("运算符有误!!!"); 135 } 136 stack.push(res+""); 137 } 138 } 139 140 141 int result=Integer.parseInt(stack.pop()); 142 System.out.println(ex+"="+result); 143 144 145 146 147 } 148 149 } 150 151 152 153 154 155 156 //使用链表存储分割好后的中缀表达式 157 public static List<String>StringToList(String ex){ 158 List<String>ls=new ArrayList<String>(); 159 int i=0; 160 String st; 161 while(i<ex.length()){ 162 if(ex.charAt(i)<48||ex.charAt(i)>57){//如果是符号,则直接添加 163 ls.add(ex.charAt(i)+""); 164 i++; 165 }else{ 166 st=""; 167 //如果是数字,则需要考虑是否为多位数 168 while((i<ex.length())&&(ex.charAt(i)>47&&ex.charAt(i)<58)){ 169 st=st+ex.charAt(i); 170 i++; 171 } 172 ls.add(st); 173 } 174 } 175 return ls; 176 } 177 178 public static int getPriority(String oper){ 179 if(oper=="*"||oper=="/"){ 180 return 1; 181 }else if(oper=="+"||oper=="-"){ 182 return 0; 183 }else{ 184 return -1; 185 } 186 } 187 188 }
运行结果:


浙公网安备 33010602011771号