C语言逆波兰式算法

发布时间 2024-01-05 19:09:16作者: 岸芷枫
  1 #include <stdio.h>
  2 
  3 //数字模式识别 
  4 #define IS_NUM(c)    (((c)>='0') && ((c)<='9') || ((c)=='.'))
  5 //符号字符识别 
  6 #define IS_OPERATOR(c) (((c)=='+') || ((c)=='-') || ((c)=='*') || ((c)=='/') || ((c)=='('))
  7 //加减符号识别 
  8 #define IS_AS(c) (((c)=='+') || ((c)=='-'))
  9 //乘除符号识别 
 10 #define IS_MD(c) (((c)=='*') || ((c)=='/'))
 11 
 12 
 13 //逆波兰式 识别原则
 14 //1、遇见数字直接压入输出数组里边;
 15 //2、遇见乘除符号,则先把前边紧跟着的所有乘除符号逆序弹出到输出数组中 ,然后把当前的符号压入符号栈;
 16 //3、遇见加减号,则把最近前括号“(”之后的的所有符号全部弹出到输出数组中,然后压入当前符号;
 17 //4、每次遇见任何符号,都表明之前的数据识别完成,这里需要添加空格用来区分两个数据
 18 //5、如果算式刚开始或者其他符号之后出现“-”,这这个符号会被识别成符号,
 19 //   负数标志位置1,先在输出数组中压入0和空格,且在后边数据识别完成之后,直接添加“-”,用0-x的方式实现负数 
 20 //6、如果遇见前括号“(” 则直接压入符号栈;如果遇见后括号“)”,则把最近的前括号之后所有的符号逆序弹出到输出数组;
 21 //7、原式子识别完成之后,如果符号栈还有数据,则按照逆序分别弹出到输出数组中;
 22 //缺陷:没有进行括号匹配识别,也没有处理连续两个符号重新一块输入的bug,还有一个数据输入多个小数点的bug!!!!! 
 23  
 24 //例如 1.2+-42.8/2*(1*-2.56/(3-4))*(10/5+2.6)
 25 //a、根据原则1和原则3和原则4,输出数组:1.2(空格),符号栈:+
 26 //b、根据原则5、1、2,输出数组 1.2 0 42.8 - 2 符号栈:+ /
 27 //c、根据原则2,输出数组:1.2 0 42.8 - 2 /  符号栈:+ *
 28 //d、根据原则6,输出数组:1.2 0 42.8 - 2 /  符号栈:+ * (
 29 //e、根据原则1、2、3、4、5、6 输出数组:1.2 0 42.8 -2 /1 0 2.56 -*  符号栈:+ * (/(
 30 //f、根据原则1、3 输出数组:1.2 0 42.8 -2 /1 0 2.56 -*3 4 -  符号栈:+ * (/(
 31 //g、根据原则6  输出数组:1.2 0 42.8 -2 /1 0 2.56 -*3 4 -/  符号栈:+ * 
 32 //h、之前的原则,则后续结果1.2 0 42.8 -2 /1 0 2.56 -*3 4 -/*10 5 /2.6 +*+
 33 void RPN(char shuru[],char shuchu[]) {
 34     char i;    
 35     char scIndex     = 0;        //输出栈顶索引 
 36     char opera[20]    = {0};        //符号栈 
 37     char opIndex     = 0;        //符号栈顶索引 
 38     char fushu        = 0;        //负数标志位 
 39     char errNum        = OK;        //返回错误置 
 40     
 41     for(i=0;shuru[i]!='\0';i++) {
 42         if(IS_NUM(shuru[i])) {                //数据字符 
 43             shuchu[scIndex++] = shuru[i];    //把数组直接输出        
 44         } else     if(IS_MD(shuru[i])) {        //乘除字符 
 45             if(IS_NUM(shuchu[scIndex-1])) {    //添加空格来区分数据,如果是负数模式,则添加负号,下同 
 46                 shuchu[scIndex++] = ' ';    //添加数据分割的空格 
 47                 if(fushu==1) {                //负数模式 
 48                     shuchu[scIndex++] = '-';//把符号添加到结果中 
 49                     fushu=0;                //负数标志位清零 
 50                 }
 51             }            
 52             //如果是上一个字符是乘除则一个一个弹出来填充到结果中,
 53             //直到符号栈没有符号,或者遇见前括号“(”    
 54             while(IS_MD(opera[opIndex-1]) && (opIndex>0) ) {//&& (opera[opIndex-1]!='(')
 55                 shuchu[scIndex++] = opera[--opIndex];            
 56             }            
 57             opera[opIndex++] = shuru[i];    //填充当前符号到符号栈 
 58         } else if(IS_AS(shuru[i])) {        //如果是加减模式 
 59             if(IS_NUM(shuchu[scIndex-1])) {    //添加空格,区分负号,同上 
 60                 shuchu[scIndex++] = ' ';
 61                 if(fushu==1) {
 62                     shuchu[scIndex++] = '-';
 63                     fushu=0;
 64                 }
 65             }    
 66             //如果算式刚开始就是“-”,或者其他符号紧跟着“-”则这个减号起到负数所用 
 67             if((shuru[i]=='-') && ((scIndex==0) || (IS_OPERATOR(shuru[i-1])))) {
 68                 shuchu[scIndex++] = '0'; //先添加0 把负数处理成0-x的模式 
 69                 shuchu[scIndex++] = ' ';
 70                 fushu=1;                //负数标志位 
 71             } else {
 72                 while((opIndex>0) && (opera[opIndex-1]!='(')) {//把前括号之前的符号全部弹出 
 73                     shuchu[scIndex++] = opera[--opIndex];            
 74                 }    
 75                 opera[opIndex++] = shuru[i];//压入当前符号                
 76             }            
 77             
 78         } else if(shuru[i]=='(') {                 //如果是前括号  则直接压入括号 
 79             if(IS_NUM(shuchu[scIndex-1])) {        //添加空格,区分负号,同上 
 80                 shuchu[scIndex++] = ' ';
 81                 if(fushu==1) {
 82                     shuchu[scIndex++] = '-';
 83                     fushu=0;
 84                 }
 85             }    
 86             opera[opIndex++] = shuru[i];        //压入前括号 
 87         } else if(shuru[i]==')') {                //如果是后括号,则直接弹出前括号后边的所有符号 
 88             if(IS_NUM(shuchu[scIndex-1])) {
 89                 shuchu[scIndex++] = ' ';
 90                 if(fushu==1) {
 91                     shuchu[scIndex++] = '-';
 92                     fushu=0;
 93                 }
 94             }    
 95             while(opera[opIndex-1]!='(') {         //弹出前括号之后的所有符号 
 96                 shuchu[scIndex++] = opera[--opIndex];            
 97             }        
 98             opIndex--;                            //栈顶减1,剔除前括号 
 99         }
100     }
101     //puts(shuchu);    
102     while((opIndex>0)) {                        //如果循环之后符号栈还有数据,则逆序弹出 
103         shuchu[scIndex++] = opera[--opIndex];
104     }    
105 }
106 
107 //根据逆波兰式计算数据原则
108 //1、遇见数据进行数字识别,注意识别的时候有整数和小数模式,遇见空格,表明当前数据识别完成,识别完成的数据压入数据栈 ; 
109 //2、如果遇见符号,则按照顺序弹出两个数据,然后这两个数据按照顺序进行符号匹配的运算,结果压入数据栈; 
110 //3、所有数据计算完成之后,数据栈就留下唯一结果,就是最终结果 
111 //例如上边逆波兰式 1.2 0 42.8 -2 /1 0 2.56 -*3 4 -/*10 5 /2.6 +*+
112 //a、先压入1.2 0 42.8 ,当看见符号,则弹出42.8和0 ,然后计算0-42.8,把结果压入数据栈,1.2 -42.8 
113 //b、然后出现2,则先把2压入数据栈;
114 //c、遇见/,则弹出2和-42.8,计算-42.8/2结果为-21.4压入数据栈,结果为1.2 -21.4
115 //d、后边的数据以此类推 
116 float RPNOperation (char shuru[]) {        
117     char i;
118     float value[10]={0};    //数据和计算数据的栈 
119     char vIndex=0;        //数据栈顶索引 
120     char xs=0;            //小数标志位 
121     float xishu=0.1;    //小数系数 
122     float s0,s1;        //运算数据变量 
123     
124     
125     for(i=0;shuru[i] != '\0';i++) {         //遍历所有逆波兰式字符串 
126         if(IS_NUM(shuru[i])) {                //数字模式 
127             if(shuru[i]=='.') {                //如果判断小数点,则小数标志位置1 
128                 xs=1;
129             } else {                        //纯数字模式,则计算数据 
130                 if(xs==0) {                    //整数模式计算方法,a=a*10+b,其中a是上一次数据,b是当前数据 
131                     value[vIndex] = value[vIndex]*10 + (shuru[i]-'0');    
132                  } else if(xs==1){            //如果是小数模式,则每一个新数据都要倍一个小数系数 
133                      value[vIndex] += xishu*(shuru[i]-'0');
134                      xishu/=10;                //小数系数缩小到原来的十分之一,供下次使用 
135                  }
136             }              
137         } else if(shuru[i]==' ') {            //如果是空格,则表明上边的数据已经完结 
138             xs=0;                            //小数标志位清零 
139             vIndex++;                         //数据栈加1 
140             xishu=0.1;                        //小数系数恢复到0.1 
141         } else if(IS_OPERATOR(shuru[i])) {    //如果遇见符号 
142             s0=value[--vIndex];                //弹出第一数据 
143             value[vIndex] = 0;                //原数据必须清零,否则,影响下一次数据识别 
144             s1=value[--vIndex];                //弹出第二个数据 
145             switch (shuru[i]){                //根据符号进行计算 
146                 case '+':value[vIndex]=s1+s0;break;
147                 case '-':value[vIndex]=s1-s0;break;
148                 case '*':value[vIndex]=s1*s0;break;
149                 case '/':value[vIndex]=s1/s0;break;
150             }
151             vIndex++;                         
152             xs=0;
153             xishu=0.1;
154         }
155     }
156     return value[0];                        //运算完成之后,栈里边只留下最终结果 
157 }
158 
159 main() {
160     //带带括号嵌套,带负数的运算式 
161     char shuru[]="1.2+-42.8/2*(1*-2.56/(3-4))*(10/5+2.6)";
162     //逆波兰式输出数组 
163     char shuchu[35]={0};
164     float v;                //最终结果 
165     RPN(shuru,shuchu);        //计算逆波兰式 
166     puts(shuchu);            //打印逆波兰式 
167     v=RPNOperation(shuchu);    //计算数据结果 
168     printf("%f",v);            //打印结果 
169 }