中缀表达式求值

所用知识:C语言,堆栈操作

算法思想来自慕课浙江大学《数据结构》陈老师,何老师

笔记:

1.堆栈:
    1.1 引子    
        一种数据结构,在函数调用,表达式求值等都有广泛的应用
        中缀表达式:a+b*c-d/e:生活中经常使用,但是计算机不好识别
        后缀表达式:abc*+dc/-:生活中不好使用,但计算机容易识别

        例:
        总结:因此需要一种存储方法,能顺序的存储运算数,在需要时倒叙输出。-->堆栈有
        堆栈的特点:后入先出。

    1.2堆栈的操作
    操作集:长度为maxSize的堆栈S ==> stack,堆栈的元素elementType,那么如下的操作
        stack createStack(int maxSize);//生成空堆栈,其最大长度为maxSize
        int isFull(stack s,int maxSize);//判断栈s是否为空
        void push(stack  s,elementType item);//将元素压入堆栈
        int isEmpty(stack s);//判断堆栈是否为空
        elementType pop(stack s);//删除并返回栈顶元素
        
        1.2.1
            用数组来表示堆栈的方法可以参照文件夹下面的同级目录的文件stackArray.c
            同时还有使用一个数组来表示两个堆栈,twoStack.c
        
        1.2.2使用链表来模拟堆栈
            因为链表有两头,但是堆栈的头指针我们会选择链表的头节点,因为便于删除操作,尾节点不方便进行删除操作
            下面是模拟的示意图
                head(头指针,没有元素的) --> node1(top指针) --> node2(堆栈中的元素) --> node3 --> node4
            代码可以见:stackLinkList.c

        1.2.3 利用堆栈进行表达式求值
            我们平时所见到的表达式都是中缀表达式,但是如果想求表达式的值,先把中缀表达着中文后缀表达式,
            在利用堆栈对后缀表达式进行求值

            中缀表达式转后缀表达式的思路;
                首先看一个简单的:
                中缀表达式:2 + 9 / 3 - 5    后缀表达式:2 9 3 / + 5 -

                通过对比我们发现,中缀表达式和后缀表达式的数字顺序并没有发生改变,只是符号位置发生了改变
                所以,我们可以构思,使用一个栈来存在运算符,遇到数字就输出,遇到符号就压栈,如果读入的符号比栈顶的符号
                优先级高,就压栈,否则就弹栈并输出
                下面是中缀表达式:2 + 9 / 3 - 5压栈和弹栈的具体步骤
                输出        堆栈内元素
                2           
                           +
                9           
                           /(优先级比+高,压栈)
                3           
                / +           -(首先弹出/,但是因为同级运行需要按照从左往右的运算,所以+也需要弹栈)
                5           -
                -          (元素全部读取完毕以后,-弹栈)

                所以中缀表达式:2 + 9 / 3 - 5的后缀表达式为 2 9 3 / + 5 -

                但是如果遇到带有()的表达式怎么办:遇到"("把"("压入栈中,此时栈中的"("运算级别最低,在按照上面的运算符的运算规则来
                进行压栈和弹栈。直到读取到")",才把"("弹栈,但是对"("和")"不进行输出

                举个例子:
                求下面中缀表达式:2 * (9+6/3-5)+4的后缀表达式

                输出            堆栈内元素(top->bottom)

                2
                                 *
                                 ( *
                9                 + ( *
                6            
                                 / + ( *
                3                 
                                 - ( *(首先弹出/,但是因为同级运行需要按照从左往右的运算,所以+也需要弹栈,并输出)
                    / +
                5
                -                *(遇到")",把栈里依次弹出,直到遇到第一个"(",但是对"("和")"不进行输出)
                *                +(遇到+,先弹出*,然后输出)
                4                +
                +                NULL(没有元素可读,弹出堆栈中最后一个元素)
                
                所以中缀表达式:2 * (9+6/3-5)+4的后缀表达式为: 2 9 6 3 / + 5 - * 4 +

代码实现

思路:中缀表达式先转后缀表达式在求值

只支持0-9之间的数字的+-*/以及(),支持括号里面嵌套括号,如3*(2*3-4*1+(3*5)/3)*3+2

不支持分开的括号3*(2*3-4*1+(3*5)/3)*3+2+(4/2)

如果有给出修改意见,感激不尽。写的比较匆忙,代码的复用性和注释的完整性可能不是很好

 

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<string.h>
  4 #include<math.h>
  5 #include<ctype.h>
  6 #define MAXSIZE 100
  7 
  8 
  9 #include<stdio.h>
 10 #include<stdlib.h>
 11 /*使用链表来模拟堆栈,*/
 12 
 13 
 14 
 15 /*=======================================================定义double类型的堆栈链式存储并进行相关的压栈,弹栈等操作===============================================================*/
 16 
 17 //定义double类型的堆栈的链式存储
 18 typedef struct node3{
 19     double element;
 20     struct node3 *next;
 21 }integerSta,*pIntegerStack;
 22 
 23 //构造一个double类型的链式栈
 24 pIntegerStack createIntegerEmptyStack(){
 25     pIntegerStack stack;
 26     stack = (pIntegerStack)malloc(sizeof(integerSta));
 27     if(stack){
 28         stack->next=NULL;
 29     }
 30     return stack;
 31 }
 32 
 33 //判断double类型的链式栈是否为空
 34 int isIntegerEmpty(pIntegerStack stack){
 35     if(stack->next==NULL){
 36         return 1;
 37     }else{
 38         return 0;
 39     }
 40 }
 41 
 42 //压栈
 43 void pushInteger(pIntegerStack stack,double element){
 44     pIntegerStack node = (pIntegerStack)malloc(sizeof(integerSta));
 45     node->element=element;
 46     node->next=stack->next;
 47     stack->next=node;
 48 }
 49 
 50 //弹栈
 51 double popInteger(pIntegerStack stack){
 52     double element;
 53     pIntegerStack topHead;
 54     if(isEmpty(stack)){
 55         printf("the stack is empty,can not pop");
 56         return;
 57     }else{
 58         topHead = stack->next;
 59         stack->next = topHead->next;
 60         element = topHead->element;
 61         free(topHead);
 62         return element;
 63     }
 64 }
 65 
 66 //取栈顶元素
 67 double getIntegetStackTopElement(pIntegerStack stack){
 68     return (stack->next->element);
 69 }
 70 
 71 //打印栈内元素
 72 void toStringInteger(pIntegerStack stack){
 73     pIntegerStack top = stack->next;
 74     printf("toString:");
 75     while(top!=NULL){
 76         printf("%f ",top->element);
 77         top=top->next;
 78     }
 79     printf("\n");
 80 }
 81 
 82 
 83 
 84 
 85 /*================================================定义一个存储字符的线性表=========================================================================*/
 86 
 87 
 88 
 89 //构造一个线性表存储后缀表达式
 90 typedef struct node2{
 91     char data[MAXSIZE];
 92     int length;
 93 }li,*pList;
 94 
 95 
 96 
 97 //初始化线性表
 98 pList createEmptyList(){
 99     pList p;
100     p = (pList)malloc(sizeof(li));
101     if(p){
102         p->length=-1;
103     }
104     return p;
105 }
106 
107 //向线性表中插入元素
108 void insert(pList list,char c){
109     if(list){
110         list->data[++(list->length)]=c;
111     }
112 }
113 
114 //将线性表中的元素打印
115 void toStringList(pList list){
116     int i;
117     for(i=0;i<=list->length;i++){
118         printf("%c ",list->data[i]);
119     }
120     printf("\n");
121 
122 }
123 
124 
125 
126 /*==================================================定义一个字符栈并进行相关操作=================================================================*/
127 //定义字符栈
128 typedef struct node{
129     char element;
130     struct node *next;
131 }sta,*pStack;
132 
133 //创建一个空的字符链式栈
134 pStack createEmptyStack(){
135     pStack stack;
136     stack = (pStack)malloc(sizeof(sta));
137     if(stack){
138         stack->next=NULL;
139     }
140     return stack;
141 }
142 
143 //判断链式栈是否为空
144 int isEmpty(pStack stack){
145     if(stack->next==NULL){
146         return 1;
147     }else{
148         return 0;
149     }
150 }
151 
152 //把元素压入栈
153 void push(pStack stack,char element){
154     pStack node = (pStack)malloc(sizeof(sta));
155     node->element=element;
156     node->next=stack->next;
157     stack->next=node;
158 }
159 
160 //把元素弹栈
161 char pop(pStack stack){
162     char element;
163     pStack topHead;
164     if(isEmpty(stack)){
165         printf("the stack is empty,can not pop");
166         return NULL;
167     }else{
168         topHead = stack->next;
169         stack->next = topHead->next;
170         element = topHead->element;
171         free(topHead);
172         return element;
173     }
174 }
175 
176 //获取栈顶元素
177 char getTopElement(pStack stack){
178     if(isEmpty(stack)){
179         printf("the stack is empty,can not get top element");
180         return;
181     }else{
182         return (stack->next->element);
183     }
184 }
185 
186 
187 
188 /*=============================================中缀表达式转后缀表达式=====================================================================*/
189 
190 
191 //打印字符数组
192 void charArrayToString(char *arr){
193     char *p  = arr;
194     while(*p!='\0'){
195         printf("%c ",*p);
196         p = p+1;
197     }
198 }
199 
200 
201 
202 /*
203 判断字符c是否存在字符数组arr中
204 存在,返回1
205 不存在,返回0
206 */
207 int isCharArrContainChar(char arr[],char c){
208     char *p =arr;
209     while(*p!='\0'){
210         if(*p==c){
211             return 1;
212         }
213         p = p+1;
214     }
215     return 0;
216 }
217 
218 
219 /*给定一个运算符,判断他的优先级,返回数字越大,优先级越高,例如
220     operatorPriorityArr是一个二维数组,下面是模拟的内容,优先级用户可以自定义,数组按元素优先级由低到高排列
221         0 +-    第0优先级
222         1 * /   第1优先级
223         2 ()    第2优先级
224 
225     c:等待判断优先级的运算符
226 */
227 int getCharIndex(char c,char operatorPriorityArr[][MAXSIZE],int length){
228     int i;
229     for(i=0;i<length;i++){
230         if(isCharArrContainChar(operatorPriorityArr[i],c)){
231             return i;
232         }
233     }
234     return -1;
235 }
236 
237 
238 /*
239 判断字符栈的栈顶元素的优先级和读入字符的优先级
240 参数:
241     stackTopEle:栈顶元素
242     readChar:读入的元素
243     operatorPriorityArr:用户自定义的运算符优先级二维字符数组,数组按元素优先级由低到高排列
244     length:二维数组的行数
245 
246 比较规则:
247     1.如果读入的字符为"(",那么"("的优先级最高,直接压栈
248     2.如果栈顶元素为"(",其优先级最低,eadChar直接入栈
249     3.如果读入的元素readChar优先级大于栈顶元素,则readChar入栈。例如eadChar为"*" topChar为"+",则"*"入栈
250     4.如果读入的元素readChar优先级小于或者等于(因为运算需要按照从左往右的顺序)栈顶元素,则topChar弹栈并输出(记录)。
251         再次判断readChar和当前栈顶元素的优先级,如果当readChar还是优先级小于或者等于当前栈顶元素,接着弹栈并输出(记录)。
252         一直比较,直到readChar的优先级大于栈顶元素或者栈为空。
253     5.如果readChar为")",一直弹栈到到第一次遇到"(",并把"("也弹栈,对"("和")"不做输出,其运算符弹栈且输出(记录)
254 
255         返回值:
256             1:压栈
257             0:读入")" 直到把第一个"("弹栈栈为止
258             2:弹出当前的栈顶元素,并继续比较
259 */
260 int compareOperatorChar(char stackTopEle,char readChar,char operatorPriorityArr[][MAXSIZE],int length){
261     int index1,index2;
262     if(stackTopEle=='('){
263         return 1;//栈为空,直接压栈
264     }else if(readChar==')'){
265         return 0;//读入遇到")",直到把第一个"("弹栈栈为止
266     }else{
267         //获取两个运算符的优先级
268         index1 = getCharIndex(stackTopEle,operatorPriorityArr,length);
269         index2 = getCharIndex(readChar,operatorPriorityArr,length);
270         if(index1<index2){//比较优先级
271             return 1;
272         }else{
273             return 2;
274         }
275     }
276 }
277 
278 
279 /*
280 根据优先级的返回结果进行对应的压栈和弹栈操作
281 参数:
282     stack:准备好的空字符栈
283     readChar:读入的字符
284     operatorPriorityArr:定义的优先级规则
285     list:储存后缀表达式的字符线性表
286     length:二维数组的行数
287 */
288 void comparePriority(pStack stack,char readChar,char operatorPriorityArr[][MAXSIZE],pList list,int length){
289     if(isEmpty(stack)){
290         push(stack,readChar);
291         return 1;
292     }else{
293         char topEle = getTopElement(stack);
294         int result = compareOperatorChar(topEle,readChar,operatorPriorityArr,length);
295         if(result==0){
296             while(getTopElement(stack)!='('){
297                 insert(list,pop(stack));
298             }
299             pop(stack);
300             return;
301         }else if(result==1){
302             push(stack,readChar);
303             return;
304         }else{
305             insert(list,pop(stack));
306             //递归再次比较
307             comparePriority(stack,readChar,operatorPriorityArr,list,length);
308         }
309     }
310 }
311 
312 
313 /*
314 根据中缀表达式或者后缀表达式,转换规则:
315     1.对于数字,进行原样的输出或者记录
316     2.对于运算符,根据优先级进行压栈弹栈操作,优先级比较规则参照上面
317 参数:
318     stack:准备好的空字符栈
319     arr:中缀表达式的字符数组,支持空格隔开
320     operatorPriorityArr:定义的优先级规则
321     list:储存后缀表达式的字符线性表
322     length:二维数组的行数
323 */
324 char* getBehindExpress(pStack stack,char *arr,char operatorPriorityArr[3][MAXSIZE],pList list,int length){
325     char *p  = arr;
326     while(*p!='\0'){
327         if(*p>='0' && *p<='9'){
328             insert(list,*p);
329         }else if(*p==' '){
330             p = p+1;
331             continue;
332         }else if(getCharIndex(*p,operatorPriorityArr,length)!=-1){//判断运算符是否和法
333                 comparePriority(stack,*p,operatorPriorityArr,list,length);
334         }else{
335             printf("the operational character is illegal\n");
336             return "error";
337         }
338         p = p+1;
339     }
340     //当数字读取完毕后,要把栈里面的运算符全部弹栈
341     while(!isEmpty(stack)){
342         insert(list,pop(stack));
343     }
344 }
345 
346 //打印字符栈里面的元素
347 void toString(pStack stack){
348     pStack top = stack->next;
349     printf("toString:");
350     while(top!=NULL){
351         printf("%c ",top->element);
352         top=top->next;
353     }
354     printf("\n");
355 }
356 
357 
358 
359 
360 /*==================================================计算后缀表达式的值==========================================================================*/
361 /*计算规则如下:
362 求后缀表达式的值
363             6 2 / 3 - 4 2 * + =
364 
365             后缀表达式的求解原理:遇到数值先记录(压栈),遇到符号才计算(弹栈两个元素)。计算离符号最近的两个数
366             1.6 2 / ==> 3 压栈
367             2.3 3 - ==> 0 压栈
368             3.0 4 2 * ==> 0 8
369             4.0 8 + ==>8
370             5.8 = ==> 8
371 */
372 double getValueByAfterExpress(pList list,pStack stack){
373     int i,store;
374     double temp,a1,a2;
375     for(i=0;i<=list->length;i++){
376         //printf("test");
377         char c = list->data[i];
378         if(c>='0' && c<='9'){
379             store = c-'0';//字符转换为数字
380             temp = store*1.0;//整形转换为double型
381             //printf("double:%f\n",temp);
382             pushInteger(stack,temp);//数字就压栈
383         }else{
384             //弹栈并根据运算符做运算
385             double a1 = popInteger(stack);
386             double a2 = popInteger(stack);
387             if(list->data[i]=='+'){
388                 temp = a1+a2;
389                 pushInteger(stack,temp);
390             }
391 
392             if(list->data[i]=='-'){
393                 temp = a2-a1;
394                 pushInteger(stack,temp);
395             }
396             if(list->data[i]=='*'){
397                 temp = a1*a2;
398                 pushInteger(stack,temp);
399             }
400             if(list->data[i]=='/'){
401                 temp = a2/a1;
402                 pushInteger(stack,temp);
403             }
404 
405         }
406         //toStringInteger(stack);
407     }
408     //最终的栈顶元素即为所求的值
409     return getIntegetStackTopElement(stack);
410 }
411 
412 
413 
414 void main(){
415     int n = 3,i;
416     pStack stack  = createEmptyStack();
417     pStack numberStack   = createIntegerEmptyStack();
418     pList list = createEmptyList();
419 
420     char arr1[] = "2 * ( 9 + 6 / 3 - 5 ) + 4";
421     char arr2[] = "2 + 9 / 3 - 5";
422     char arr3[] = "3*(2*3-4*1+(3*5)/3)*3+2";
423     char operatorPriorityArr[3][MAXSIZE]={"+-","*/","()"};
424     //计算二维数组的行数
425     int length=sizeof(operatorPriorityArr)/sizeof(operatorPriorityArr[0]);
426     //char operatorArr[] = "+-*/()";
427     getBehindExpress(stack,arr3,operatorPriorityArr,list,length);
428     //toStringList(list);
429     double value = getValueByAfterExpress(list,numberStack);
430     printf("the express %s caculate result is %f",arr3,value);
431     //double c = (double)('9.23');
432     //printf("test:%f",c);
433     //printf("%d",length);
434 }
表达式求值

 

转载于:https://www.cnblogs.com/yghjava/p/6629622.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值