今天要练习的算法是通过中缀表达式生成表达式树。中缀、前缀、后缀表达式的概念就不赘述了,学习链接:中缀、前缀、后缀表达式。
参考代码学习链接:表达式树—中缀表达式转换成后缀表达式(一)。
- 【迭代 ①】:识别单个运算符,进行分割,通过递归的思想构建表达式树。
举例:输入“1+2”,输出。
Java code of phase[1]:
1 void Express2BTree(String str){ 2 root=Express2BTreeProc(str); 3 } 4 private BTNode Express2BTreeProc(String str){ 5 BTNode parent=new BTNode(); 6 boolean isSet[]={false,false}; //【0】:left,【1】:right 7 String tmp=new String(); //临时字符串 8 for(int i=0;i<str.length();i++){ 9 char ch=str.charAt(i); 10 if(ch>=48 && ch<=57){ //是数字 11 tmp+=ch; 12 } 13 else if(ch=='+' || ch=='-' || ch=='*' || ch=='/'){ 14 parent.data=String.valueOf(ch); 15 if(! isSet[0]){ //左子树未构造 16 isSet[0]=true; 17 parent.lChild=Express2BTreeProc(tmp); 18 tmp=new String(""); //归零初始化 19 } 20 } 21 } 22 if(isSet[0] && (! isSet[1])){//右子树未构造 23 isSet[1]=true; 24 parent.rChild=Express2BTreeProc(tmp); 25 tmp=new String(""); //归零初始化 26 } 27 if(! isSet[0]) parent.data=tmp;//如果函数处理的全是数字(叶子节点),那么就返回叶子节点 28 return parent; 29 }
逻辑盲区:
1、启动构造右子树的 if 语句不能嵌套在上方的 if 中,否则不能触发。
2、数字0~9的ascii码是[ 48 , 57 ],故应写<=、>=。
- 【迭代 ②】:判断多个表达式。
举例:输入“1+2+3”,输出:
代码改进:在临时字符串递加段,加入【或】判断条件 isSet[0] ,如果左子树已构造,继续扫描、递加。
- 【迭代 ③】:识别优先级。*、/ 的优先级比+、- 的要高。
(在这里我修改了toString打印树函数,填充符由*变为space,避免混淆)
如果代码按原先的方式跑,结果是:
但是根据运算符优先级,应该是:
修改两处代码:
1.递归函数中引入 only_Have_Priority 变量:
1 boolean only_Have_Priority=false; 2 if(( str.indexOf("+")<0 && str.indexOf("-")<0 ) 3 && 4 ( str.indexOf("*")>=0 || str.indexOf("/")>=0 )) 5 only_Have_Priority=true; 6 //能够找到 * / 、不能找到 + -
2.触发对表达式进行分割的判断语句中引入一个【与】判断条件:
((!only_Have_Priority)&&(ch=='*' || ch=='/'))
完整代码:
Java code of phase[3]:
1 void Express2BTree(String str){ 2 root=Express2BTreeProc(str); 3 } 4 private BTNode Express2BTreeProc(String str){ 5 BTNode parent=new BTNode(); 6 int i; 7 boolean isSet[]={false,false}; //【0】:left,【1】:right 8 // boolean havaAddOrSub = ( str.indexOf("+")<0 || str.indexOf("-")<0 ) ? false : true; 9 10 boolean only_Have_Priority=false; 11 if(( str.indexOf("+")<0 && str.indexOf("-")<0 ) 12 && 13 ( str.indexOf("*")>=0 || str.indexOf("/")>=0 )) 14 only_Have_Priority=true; 15 //能够找到 * / 、不能找到 + - 16 17 String tmp=new String(); //临时字符串 18 19 for(i=0;i<str.length();i++){ 20 char ch=str.charAt(i); //是数字、或者左树已构造 || (havaAddOrSub && (ch=='' || ch=='-') ) 21 if( (ch>=48 && ch<=57 ) || isSet[0] || ((!only_Have_Priority)&&(ch=='*' || ch=='/')) ){ 22 tmp+=ch; 23 } 24 else if(ch=='+' || ch=='-' || ch=='*' || ch=='/'){ 25 parent.data=String.valueOf(ch); 26 if(! isSet[0]){ //左子树未构造 27 isSet[0]=true; 28 parent.lChild=Express2BTreeProc(tmp); 29 tmp=new String(""); //归零初始化 30 } 31 } 32 }
逻辑盲点:
对 only_Have_Priority 进行赋值时,应该是【与】而不是或。想错了。
测试:
输入:1*2+3*4
输出:
输入:1*2+3*4+5*6
输出:
- 【迭代 ④】:小括号的优先级应最高
运行中出现bug。经查是原来的 only_Have_Priority 判断语句的不足。修改之。
加入了堆栈思想的括号判断语句。
Java code of phase[4]:
1 void Express2BTree(String str){ 2 root=Express2BTreeProc(str); 3 } 4 private BTNode Express2BTreeProc(String str){ 5 BTNode parent=new BTNode(); 6 int i; 7 boolean isSet[]={false,false}; //【0】:left,【1】:right 8 // boolean havaAddOrSub = ( str.indexOf("+")<0 || str.indexOf("-")<0 ) ? false : true; 9 10 boolean only_Have_Priority=false; 11 int inBracket=0; //判断当前字符是否在括号中 12 13 boolean havaMulti=false; 14 boolean havaAdd=false; 15 for(i=0;i<str.length();i++){ 16 char ch=str.charAt(i); 17 if(ch=='(') inBracket++; 18 else if(ch==')') inBracket--; 19 else if(inBracket==0){ //在括号内 20 if(ch=='*' || ch == '/') havaMulti=true; 21 else if(ch=='-' || ch == '+') havaAdd=true; 22 } 23 } 24 if((!havaAdd) && (havaMulti)) only_Have_Priority=true; 25 //能够找到 * / 、不能找到 + - 26 27 inBracket=0; 28 29 String tmp=new String(); //临时字符串 30 31 for(i=0;i<str.length();i++){ 32 char ch=str.charAt(i); //是数字、或者左树已构造 33 if(ch=='('){ 34 if(inBracket>0) tmp+=ch;//括号内的括号 35 inBracket++; 36 } 37 else if(ch==')'){ 38 inBracket--; 39 if(inBracket>0) tmp+=ch; 40 } 41 else if( (ch>=48 && ch<=57 ) 42 || isSet[0] 43 || ((!only_Have_Priority)&&(ch=='*' || ch=='/')) //不存在(只有1*2),也就是1*2+3 44 || inBracket>0 ){ 45 tmp+=ch; 46 } 47 else if(ch=='+' || ch=='-' || ch=='*' || ch=='/'){ 48 parent.data=String.valueOf(ch); 49 if(! isSet[0]){ //左子树未构造 50 isSet[0]=true; 51 parent.lChild=Express2BTreeProc(tmp); 52 tmp=new String(""); //归零初始化 53 } 54 } 55 } 56 57 if(isSet[0] && (! isSet[1])){//右子树未构造 58 isSet[1]=true; 59 parent.rChild=Express2BTreeProc(tmp); 60 tmp=new String(""); //归零初始化 61 } 62 if(! isSet[0]) parent.data=tmp;//如果函数处理的全是数字(叶子节点),那么就返回叶子节点 63 return parent; 64 }
测试输入:((3*4)/(1+2))*((1+1)/(1-2))
测试输出:
测试输入:(1+2)*3
测试输出:
【在一次测试中发现异常】:
输入:(1+2)*3-2
输出:
然后改了一个小时bug。我的函数写的还是有问题,反正现在无论怎么输入,只要是一个正常的表达式,都没什么问题了。
修改BUG后代码:
1 void Express2BTree(String str){ 2 root=Express2BTreeProc(str); 3 } 4 private BTNode Express2BTreeProc(String str){ 5 int i; 6 //首尾括号剥夺 7 if(str.length()>1 && str.charAt(0)=='(' && str.charAt(str.length()-1)==')'){ 8 String tmp=str.substring(1, str.length()-1); 9 //是否存在括号内字符? 10 boolean haveInnerChar=false; 11 int inBracket=0; 12 for(i=0;i<str.length();i++){ 13 char ch=str.charAt(i); 14 if(ch=='(') inBracket++; 15 else if(ch==')') inBracket--; 16 else if(inBracket==0){ //在括号内 17 haveInnerChar=true; 18 } 19 } 20 if(!haveInnerChar) str=tmp; 21 } 22 BTNode parent=new BTNode(); 23 24 boolean isSet[]={false,false}; //【0】:left,【1】:right 25 // boolean havaAddOrSub = ( str.indexOf("+")<0 || str.indexOf("-")<0 ) ? false : true; 26 27 boolean only_Have_Priority=false; 28 int inBracket=0; //判断当前字符是否在括号中 29 30 /* if(( str.indexOf("+")<0 && str.indexOf("-")<0 ) 31 && 32 ( str.indexOf("*")>=0 || str.indexOf("/")>=0 )) 33 only_Have_Priority=true;*/ 34 boolean havaMulti=false; 35 boolean havaAdd=false; 36 for(i=0;i<str.length();i++){ 37 char ch=str.charAt(i); 38 if(ch=='(') inBracket++; 39 else if(ch==')') inBracket--; 40 else if(inBracket==0){ //在括号内 41 if(ch=='*' || ch == '/') havaMulti=true; 42 else if(ch=='-' || ch == '+') havaAdd=true; 43 } 44 } 45 if((!havaAdd) && (havaMulti)) only_Have_Priority=true; 46 //能够找到 * / 、不能找到 + - 47 48 inBracket=0; 49 50 String tmp=new String(); //临时字符串 51 52 for(i=0;i<str.length();i++){ 53 char ch=str.charAt(i); //是数字、或者左树已构造 54 if(ch=='('){ 55 tmp+=ch;//括号内的括号 56 inBracket++; 57 } 58 else if(ch==')'){ 59 inBracket--; 60 tmp+=ch; 61 } 62 else if( (ch>=48 && ch<=57 ) 63 || isSet[0] 64 || ((!only_Have_Priority)&&(ch=='*' || ch=='/')) //不存在(只有1*2),也就是1*2+3 65 || inBracket>0 ){ 66 tmp+=ch; 67 } 68 else if(ch=='+' || ch=='-' || ch=='*' || ch=='/'){ 69 parent.data=String.valueOf(ch); 70 if(! isSet[0]){ //左子树未构造 71 isSet[0]=true; 72 parent.lChild=Express2BTreeProc(tmp); 73 tmp=new String(""); //归零初始化 74 } 75 } 76 } 77 78 if(isSet[0] && (! isSet[1])){//右子树未构造 79 isSet[1]=true; 80 parent.rChild=Express2BTreeProc(tmp); 81 tmp=new String(""); //归零初始化 82 } 83 if(! isSet[0]) parent.data=tmp;//如果函数处理的全是数字(叶子节点),那么就返回叶子节点 84 return parent; 85 }