中缀表达式变后缀表达式算法

合集下载

中缀转后缀表达式算法

中缀转后缀表达式算法

中缀转后缀表达式算法
中缀表达式转后缀表达式(也称为逆波兰表达式)是一种将中缀表达式转换为后缀表达式的算法。

它的基本思想是将中缀表达式转换为一个后缀表达式,其中操作符位于操作数之后,而不是操作数之前。

中缀表达式转后缀表达式的算法步骤如下:
1. 从左到右扫描中缀表达式;
2. 如果读取的是操作数,则将其压入堆栈;
3. 如果读取的是运算符,则比较其与栈顶运算符的优先级:
(1)如果栈顶运算符的优先级高于或等于读取的运算符,则将栈顶运算符弹出,并将其压入输出队列;
(2)如果栈顶运算符的优先级低于读取的运算符,则将读取的运算符压入堆栈;
4. 重复步骤2和3,直到表达式末尾;
5. 将栈中所有元素依次弹出,压入输出队列,完成中缀表达式到后缀表达式的转换。

中缀表达式转后缀表达式算法的优点是它可以有效地将中缀表达式转换为后缀表达式,从而简化表达式的计算过程。

它的缺点是它需要记住操作符的优先级,并且需要使用堆栈来存储操作符,这可能会增加算法的复杂度。

总之,中缀表达式转后缀表达式算法是一种有效的算法,它可以有效地将中缀表达式转换为后缀表达式,从而简化表达式的计算过程。

将中缀表达式转换成后缀表达式的三种方法

将中缀表达式转换成后缀表达式的三种方法

将中缀表达式转换成后缀表达式的三种方法中缀表达式是我们平常最常见的表达式形式,但在计算机的运算过程中,我们常常需要将中缀表达式转换成后缀表达式,因为后缀表达式具有易于计算的特点。

那么,接下来我们将介绍三种将中缀表达式转换成后缀表达式的方法。

一、栈的方法这种方法是最常见的一种方法,也是比较易理解的一种方法。

我们可以借助栈来完成中缀表达式转换成后缀表达式的过程。

具体的操作如下:1. 声明一个操作符的栈stack(栈中存放操作符)和一个后缀表达式的列表res(列表中存放转换后的后缀表达式)。

2. 从左到右遍历中缀表达式。

3. 若当前字符为数字,则直接将该数字添加到res中。

4. 若当前字符为左括号“(”,则将其压入stack栈中。

5. 若当前字符为右括号“)”,则依次弹出stack栈中的操作符并加入到res中,直到遇到左括号为止。

6. 若当前字符为操作符,那么则需判断当前操作符与stack栈顶操作符的优先级,若当前操作符的优先级小于等于栈顶操作符,则弹出栈顶操作符并加入到res中,重复此步骤,直到当前操作符大于栈顶操作符优先级,最后将当前操作符压入stack栈。

7. 当遍历完整个中缀表达式后,若stack栈中还有剩余操作符,则依次弹出栈顶操作符并加入到res中。

8. 最终,res中的表达式就是转换后的后缀表达式。

二、递归调用方法这种方法是使用递归的方式来完成。

具体的操作如下:1. 若当前遍历的字符为数字,则直接输出该数字。

2. 若当前遍历的字符为左括号“(”,则递归读取该括号内的表达式。

3. 若当前遍历的字符为右括号“)”,则返回。

4. 若当前遍历的字符为操作符,“x”,“/”,“+”,“-”,则递归调用该表达式右边的操作符,比如“x”,“/”,然后再递归调用左边的操作符,比如“+”,“-”,然后输出左操作数和右操作数,最后输出当前操作符。

5. 最终,输出的表达式即为转换后的后缀表达式。

三、判断法这种方法也是比较常见的一种方法。

数据结构中缀表达式改后缀表达式

数据结构中缀表达式改后缀表达式
例如,整个 表达式的括号要省略,不影响计算顺序括号要省略。 输入形式:
程序从标准输入读入一行字符串,是一个合法的后缀表达式,数字和运 算符之间
由空格分隔。数字可以是带小数部分的浮点数。
输出形式: 向标准输出打印结果,输出只有一行,是转换后的中缀表达式。 并且 : 1、各分量(包括括号)紧密输出,不使用空格进行分隔; 2、在转换后的各运算数的出现顺序不变; 3、浮点数保留输入时的小数位数。
Node p,q,f;
//连接两个链表
if(flag==0) {
printf("错误\n"); exit(0); }
E->Lists[flag-1]->c=ch;
p=E->Lists[flag-1]; f=E->Lists[flag]->next;
while(p->next!=NULL) p=p->next;
*/
#include<stdio.h> #include<stdlib.h>
struct Expression; typedef struct Expression *Node;
struct Expressionlist; typedef struct Expressionlist *Elist;
struct Expression {
7. 之后是符号“+”,此时当前栈顶元素比这个“+”的优先级高,因此栈中元素出 栈并输出(没有比“+”号更低的优先级,所以全部出栈),总输出表达式为 9 3 1 - 3 * +.然后将当前这个符号“+”进栈。也就是说,前 6 张图的栈底的“+”是指中缀 表达式中开头的 9 后面那个“+”,而下图中的栈底(也是栈顶)的“+”是指 “9+(3-1)*3+”中的最后一个“+”。 8. 紧接着数字 10,输出,总表达式变为 9 3 1-3 * + 10。

中缀表达式转后缀表达式---栈--二叉树---四则运算

中缀表达式转后缀表达式---栈--二叉树---四则运算

中缀表达式转后缀表达式---栈--⼆叉树---四则运算 我们平常书写的四则运算表达式属于中缀表达式,形式为"9+(3-1)*3+10/2",因为所有的运算符号都在两操作数之间,所以称为中缀表达式。

我们使⽤中缀表达式来计算表达式的值,不过这种形式并不适合计算机求解。

接下来,我们将中缀表达式转化为后缀表达式,所谓的后缀表达式就是操作符位于操作数后⾯的不包含括号的算数表达式,也叫做逆波兰表达式。

1)⾸先介绍⼀种⼈⼯的转化⽅法()。

以"9+(3-1)*3+10/2"为例,按照运算的规则,找出⾸先计算的部分,这部分包含两个操作数和⼀个操作符,将操作符移动到两个操作数右侧,这就完成了第⼀部分的转换,将这部分看作⼀个操作数,按照运算规则,以相同的⽅法转换,转换过程如下:2)还可以利⽤⼆叉树求得后缀表达式,⾸先利⽤中缀表达式构造⼆叉树,数字是叶⼦节点,操作符为根节点。

每次找到“最后计算”的运算符,作为当前根节点,运算符左侧表达式作为左节点,右侧表达式作为右节点,然后递归处理()。

9+(3-1)*3+10/2对应的⼆叉树的构造过程如下图所⽰: 此⼆叉树做后序遍历就得到了后缀表达式。

对应代码:3)还可以利⽤栈来实现中缀表达式转化为后缀表达式。

转化⽅法如下所述:a.从左向右扫描表达式,如果是数字就输出,否则转b。

b.如果当前扫描的字符是")",则栈顶元素出栈并输出⼀直到栈顶元素为"(",然后删除栈顶元素"(",并不输出。

c.如果扫描的字符或者栈顶元素是“(”,扫描的字符直接⼊栈。

即使扫描的字符是")"也不会⼊栈,因为如果是")",会出栈⾄栈顶元素是"("。

d.如果扫描字符是"+"或者"-",则⼀直出栈⾄栈顶元素为"+"或者"-"或者"("。

中缀表达式转后缀表达式

中缀表达式转后缀表达式

中缀表达式转后缀表达式逆波兰表达式先说⼀下中缀表达式,平时我们使⽤的运算表达式就是中缀表达式,例如1+3*2,中缀表达式的特点就是:⼆元运算符总是置于与之相关的两个运算对象之间⼈读起来⽐较好理解,但是计算机处理起来就很⿇烦,运算顺序往往因表达式的内容⽽定,不具规律性后缀表达式,后缀表达式的特点就是:每⼀运算符都置于其运算对象之后,以上⾯的中缀表达式1+2*3为例⼦,转为后缀表达式就是123*+下⾯先分析怎么把中缀表达式转换为后缀表达式,这⾥我们考虑六种操作符'+'、'-'、'*'、'/'、'('、')',完成中缀转后缀我们需要两个数组,都以栈的⽅式来操作,⼀个数组⽤来存放后缀表达式(char num[100]),⼀个数组⽤来临时存放操作数(char opera[100])(这⾥说临时存放,是因为最后都要⼊栈到后缀表达式数组num中,这个数组就相当于⼀个中转站)1、从左往右扫描中缀表达式(这⾥我们以1*(2+3)为例)2、如果是数字那么将其直接⼊栈到数组num中3、如果是操作数,需要进⼀步判断(1)如果是左括号'('直接⼊栈到数组opera中(2)如果是运算符('+'、'-'、'*'、'/'),先判断数组opera的栈顶的操作数的优先级(如果是空栈那么直接⼊栈到数组opera),如果是左括号那么直接⼊栈到数组opera中,如果栈顶是运算符,且栈顶运算符的优先级⼤于该运算符那么将栈顶的运算符出栈,并⼊栈到数组num中,重复步骤3,如果栈顶运算符优先级⼩于该运算符,那么直接将该运算符⼊栈到opera中(3)如果是右括号')',那么说明在opera数组中⼀定有⼀个左括号与之对应(在你没输错的情况下),那么将opera中的运算符依次出栈,并⼊栈到num中,直到遇到左括号'('(注意左括号不⽤⼊栈到num)4、如果中缀表达式扫描完了,那么将opera中的操作数依次出栈,并⼊栈到num中就可以了,如果没有没有扫描完重复1-3步上⾯就是中缀表达式转后缀表达式的步骤了,下⾯⽤图来直观的了解⼀下这个过程需要注意的是:opera中操作数,越靠近栈顶,优先级越⾼,下⾯附上实现代码View Code后缀表达式的计算完成了中缀表达式转后缀表达式,接下来就是后缀表达式的计算了,后缀表达式的计算⽐中缀转后缀要稍微简单⼀点,只需要对我们转换好的后缀表达式从左往右依次扫描,并依次⼊栈就⾏了,意思是只需要⽤⼀个数组(double num[100])就OK了需要考虑的情况如下1、如果是数字,那么直接⼊栈到num中2、如果是运算符,将栈顶的两个数字出栈(因为我们考虑的运算符加、减、乘、除都是双⽬运算符,只需要两个操作数),出栈后对两个数字进⾏相应的运算,并将运算结果⼊栈3、直到遇到'\0'下⾯⽤⼏张图,来直观了解下这个过程,以上⾯转换好的后缀表达式"123+*"为例(这⾥⽤ss来存储后缀表达式,num来存储计算结果,注意不要与上⾯图中num搞混淆了)(注意:这⾥将计算结果5⼊栈后,栈顶从之前的[3]变成[2])到这⾥后缀表达式的计算就结束了,下⾯附上实现代码[](javascript:void(0)1 #include <stdio.h>2 #include <stdlib.h>34 #define MAX 10056 void JudgeFopen_s(errno_t err); /* 判断⽂件打开是否成功 */7 void ReadFile(FILE *fp, char *ss); /* 读取⽂件内容 */8 double TransformCtoD(char ch); /* 将char类型数组的每⼀个元素转换为double */9 void CalculateAndPush(double *num, int *i, int *j, char mm); /* 计算结果并⼊栈 */1011 int main()12 {13 FILE *fp;14 errno_t err;1516 char ss[MAX]; /* 存储逆波兰表达式 */17 int i = 0;18 int j = 0;19 double num[MAX]; /* 栈 */2021 err = fopen_s(&fp, "E:\\ww.txt", "r");2223 JudgeFopen_s(err); /* 判断⽂件打开是否成功 */24 ReadFile(fp, ss); /* 读取⽂件内容,存储到ss中*/2526 while (ss[i] != '\0')27 {28 if (ss[i] >= '0' && ss[i] <= '9') /* 如果是数字 */29 {30 /* 因为num是char类型的,需要转换为double类型⽅便计算 */31 num[j] = TransformCtoD(ss[i]); /* 将数字存储到栈中 */32 j++;33 i++;34 }35 else if (ss[i] == '+' || ss[i] == '-' || ss[i] == '*' || ss[i] == '/')36 {37 CalculateAndPush(num, &i, &j, ss[i]); /* 计算结果并⼊栈 */38 }39 else if (ss[i] == '\n') /* 如果是换⾏符,结束循环*/40 {41 break;42 }43 }4445 printf("%lf", num[0]);4647 return 0;48 }4950 /* Function: 计算结果并⼊栈 */51 void CalculateAndPush(double *num, int *i, int *j, char mm)52 {53 switch (mm)54 {55 case '+':56 {57 num[(*j)-2] = num[(*j)-1] + num[(*j)-2];58 (*j)--;59 (*i)++;60 break;61 }62 case '-':63 {64 num[(*j)-2] = num[(*j)-1] - num[(*j)-2];65 (*j)--;66 (*i)++;67 break;68 }69 case '*':70 {71 num[(*j)-2] = num[(*j)-1] * num[(*j)-2];72 (*j)--;73 (*i)++;74 break;75 }76 case '/':77 {78 num[(*j)-2] = num[(*j)-1] / num[(*j)-2];79 (*j)--;80 (*i)++;81 break;82 }83 default:84 {85 exit(0);86 }87 }88 }89 /* Function: 判断⽂件打开是否成功 */90 void JudgeFopen_s(errno_t err)91 {92 if (err != 0)93 {94 printf("⽂件打开失败\n");95 system("pause");96 exit(0);97 }98 }99100 /* Function: 读取⽂件内容*/101 void ReadFile(FILE *fp, char *ss)102 {103 int i = 0;104105 while (!feof(fp))106 {107 fscanf_s(fp, "%c", &ss[i]);108 i++;109 }110 ss[i-1] = '\0';111 }112113 /* Function: 将char类型数组的每⼀个元素转换为double */ 114 double TransformCtoD(char ch)115 {116 return (double)(ch - '0');117 }。

中缀转后缀表达式计算报告

中缀转后缀表达式计算报告

目录一、设计思想 (01)二、算法流程图 (02)三、源代码 (04)四、运行结果 (14)五、遇到的问题及解决 (16)六、心得体会 (16)一、设计思想(1)中缀表达式转后缀表达式并计算创建一个数组存储输入的计算表达式。

另创建一个数组储存将要生成的后缀表达式。

创建一个栈储存操作符。

对已存储的表达式数组扫描。

判断当前节点,如果是操作数或’.’,直接加入后缀表达式中,如果是操作符,则比较前一个操作符与当前操作符的优先级。

如果前一个操作符的优先级较高,则将前一个操作符加入后缀表达式中,否则将操作符压入操作符栈。

如果遇到左括号’(’,直接入栈;如果遇到右括号’)’,则在操作符栈中反向搜索,直到遇到匹配的左括号为止,将中间的操作符依次加到后缀表达式中。

当执行完以上操作,发现栈中仍有剩余操作符,则将操作符依次加到后缀表达式中。

此时中缀表达式已经转换成了后缀表达式。

对后缀表达式进行计算。

如果后缀表达式为大于0小于9的字符,则将它转换成浮点型数据并存入数栈中。

如果遇到操作符,则从数栈中提取两个数,进行相应的运算。

依次进行下去,当没有运算符是,运算结束得到最后的结果。

(2)直接表达式求值创建一个数组存储输入的计算表达式。

创建两个栈,一个字符型的栈,一个双精度型的栈。

分别用来存储字符和数。

对已存储的表达式数组扫描。

判断当前节点,如果是操作数和’.’,将字符型的操作数转换为浮点型的数后存入操作数栈。

如果是操作符则判断操作符的优先级。

如果字符栈中已存储符号的优先级小于要存入的字符的优先级,则直接让字符入操作符栈。

如果字符栈中已存储符号的优先级大于或等于要存入的字符的优先级,则取出操作符栈中的一个字符和操作数栈中的两个数进行计算,然后将结果存入操作数栈中,同上进行下去,直到字符栈中已存储符号的优先级小于要存入的字符的优先级时,将操作符存入操作符栈中。

当遇到左括号’(’,将左括号直接存入操作符栈中。

当遇到右括号’)’,则在操作符栈中反向搜索,并且每搜到一个字符就在操作数栈中取两个数进行相应的计算。

(完整版)数学表达式计算(c语言实现)

(完整版)数学表达式计算(c语言实现)

一、设计思想计算算术表达式可以用两种方法实现:1.中缀转后缀算法此算法分两步实现:先将算术表达式转换为后缀表达式,然后对后缀表达式进行计算.具体实现方法如下:(1)中缀转后缀需要建一个操作符栈op和一个字符数组exp,op栈存放操作符,字符数组用来存放转换以后的后缀表达式。

首先,得到用户输入的中缀表达式,将其存入str数组中。

对str数组逐个扫描,如果是数字或小数点,则直接存入exp数组中,当扫描完数值后,在后面加一个#作为分隔符。

如果是操作符,并且栈为空直接入栈,如果栈不为空,与栈顶操作符比较优先等级,若比栈顶优先级高,入栈;如果比栈顶优先级低或相等,出栈将其操作符存到exp数组中,直到栈顶元素优先等级低于扫描的操作符,则此操作符入栈;如果是左括号,直接入栈,如果是右括号,出栈存入exp数组,直到遇到左括号,左括号丢掉。

然后继续扫描下一个字符,直到遇到str中的结束符号\0,扫描结束。

结束后看op栈是否为空,若不为空,继续出栈存入exp数组中,直到栈为空.到此在exp数组最后加结束字符\0。

我们就得到了后缀表达式。

(2)后缀表达式计算此时需要一个数值栈od来存放数值。

对exp数组进行逐个扫描,当遇到数字或小数点时,截取数值子串将其转换成double类型的小数,存入od栈中。

当遇到操作符,从栈中取出两个数,进行计算后再放入栈中。

继续扫描,知道扫描结束,此时值栈中的数值就是计算的结果,取出返回计算结果。

2。

两个栈实现算法此算法需要两个栈,一个值栈od,一个操作符栈op。

将用户输入的数学表达式存入str数组中,对其数组进行逐个扫描。

当遇到数字或小数点,截取数值子串,将其转换成double类型的数值存入od栈中;当遇到左括号,直接入op栈;遇到右括号,op栈出栈,再从值栈od中取出两个数值,计算将其结果存入值栈中,一直进行此操作,直到操作符栈栈顶为左括号,将左括号丢掉。

如果遇到操作符,若op栈为空,直接入栈;若栈不为空,与栈顶元素比较优先等级,若比栈顶操作符优先等级高,直接入op栈,如果低于或等于栈顶优先等级,op栈出栈,再从值栈中取出两个数值,计算将其结果存入值栈中,一直进行此操作,直到栈顶优先等级低于扫描的操作符等级,将此操作符入op 栈。

论中缀表达式与后缀表达式的转换

论中缀表达式与后缀表达式的转换

论中缀表达式与后缀表达式的转换为了处理方便,编译程序常把中缀表达式首先转换成等价的后缀表达式。

介绍如何使用顺序栈这样一种数据结构实现中缀表达式向后缀表达式的转换。

标签:堆栈;中缀表达式;后缀表达式1 中缀表达式求值首先我们来看一下什么叫作中缀表达式?所谓中缀表达式是指:每个二目运算符在两个运算量的中间。

例如:a+b。

这里假设所讨论的算术运算符包括:+ 、-、*、/和括号()。

根据算术四则运算的规则:先乘除后加减、先括号内再括号外、同级别时先左后右,可以得出运算符的优先级为:()→*、/ →+、-。

如:a+b×c-(d+e)。

我们根据优先级,计算出d+e的值x,再计算出b×c的值y,然后从左到右计算a+x-y。

它的的求值过程为:自左向右扫描表达式,当扫描到a+b时不能马上计算,因为后面可能还有更高的运算。

我们可以用两个栈来处理这样的问题:对象栈s1和算符栈s2。

当自左至右扫描表达式的每一个字符时,若当前字符是运算对象,入对象栈,是运算符时,若这个运算符比栈顶运算符高则入栈,继续向后处理,若这个运算符比栈顶运算符低则从对象栈出栈两个运算量,从算符栈出栈一个运算符进行运算,并将其运算结果入对象栈,继续处理当前字符,直到遇到结束符。

2 后缀表达式求值所谓后缀表达式,是指运算符在运算对象之后。

在后缀表达式中,不再引入括号,所有的计算按运算符出现的顺序,严格从左向右进行,而不用再考虑运算规则和级别。

例如:abcd/-e*+。

从左向右,首先计算/,即c/d的值x,然后计算b-x的值y,再计算y*e的值z,最后计算a+z。

计算一个后缀表达式,算法上比计算一个中缀表达式简单的多。

这是因为表达式中即无括号又无优先级的约束。

具体做法:只使用一个对象栈,当从左向右扫描表达式时,每遇到一个操作数就送入栈中保存,每遇到一个运算符就从栈中取出两个操作数进行当前的计算,然后把结果再入栈,直到整个表达式结束,这时送入栈顶的值就是结果。

算法笔记--中缀表达式转后缀表达式后缀表达式计算

算法笔记--中缀表达式转后缀表达式后缀表达式计算

算法笔记--中缀表达式转后缀表达式后缀表达式计算中缀表达式转后缀表达式规则中缀表达式a + b*c + (d * e + f) * g,转换成后缀表达式则为a b c * + d e * f + g * +转换过程需要⽤到栈,具体过程如下:1 如果遇到操作数,我们就直接将其输出。

2 如果遇到操作符,则我们将其放⼊到栈中,遇到左括号时我们也将其放⼊栈中。

3 如果遇到⼀个右括号,则将栈元素弹出,将弹出的操作符输出直到遇到左括号为⽌。

注意,左括号只弹出并不输出。

4 如果遇到任何其他的操作符,如+, *, (等,从栈中弹出元素直到遇到发现更低优先级的元素(或者栈为空)为⽌。

弹出完这些元素后,才将遇到的操作符压⼊到栈中。

有⼀点需要注意,只有在遇到 )的情况下我们才弹出( ,其他情况我们都不会弹出( 。

即:若操作符op的优先级⾼于栈顶操作符的优先级,则压⼊操作符栈若操作符op的优先级⼩于等于栈顶操作符的优先级,则将操作栈的操作符不断弹出到后缀表达式中,直到op的优先级⾼于栈顶操作符的优先级5 如果我们读到了输⼊的末尾,则将栈中所有元素依次弹出。

实例a +b *c + (d *e + f) * g1. ⾸先读到a,直接输出。

2. 读到“+”,将其放⼊到栈中。

3. 读到b,直接输出。

此时栈和输出的情况如下:4. 读到“*”,因为栈顶元素"+"优先级⽐" * " 低,所以将" * "直接压⼊栈中。

5. 读到c,直接输出。

此时栈和输出情况如下:6. 读到" + ",因为栈顶元素" * "的优先级⽐它⾼,所以弹出" * "并输出,同理,栈中下⼀个元素" + "优先级与读到的操作符" + "⼀样,所以也要弹出并输出。

然后再将读到的" + "压⼊栈中。

3.3-2 中缀表达式到后缀表达式的转换

3.3-2 中缀表达式到后缀表达式的转换

堆栈和队列Content堆栈1队列2表达式计算3递归4PART THREE表达式计算•表达式的概念•后缀表达式求值•中缀表达式到后缀表达式的转换中缀表达式到后缀表达式的转换注意:⚫只考虑左结合的双目运算⚫中缀表达式是由运算符、操作数和括号组成a / (b -c) + d * e 中缀表达式后缀表达式a b c -/ d e * +(输入)(输出)1.初始化堆栈,并将“#”进栈;2.顺序扫描中缀表达式中的每一个元素(这里的元素是指表达式中的操作数、操作符或界符),执行如下步骤:步骤①:若当前扫描元素为操作数,则直接输出;步骤②:若当前扫描元素为“) ”,则连续出栈输出,直到遇到“( ”出栈为止(“(”只出栈,不输出);步骤③:若当前扫描元素为操作符或“(”,则将该元素的栈外优先级与栈顶元素的栈内优先级进行大小比较:若前者较小,则连续出栈输出,直到前者大于后者时,停止出栈。

此时,再将该元素进栈。

3.扫描结束,输出栈中其他元素(#除外)。

转换算法中操作符优先级定义•栈内优先级(In-Stack Priority, ISP)•栈外优先级(InComing Priority, ICP )操作符# ( */ +-)ICP(外)0 7 4 2 1ISP(内)0 1 5 3 7a (/bc -)d +*e#1.初始化堆栈,并将“#”进栈;2.顺序扫描中缀表达式中的每一个元素,执行如下步骤:步骤①:若当前扫描元素为操作数,则直接输出;步骤②:若当前扫描元素为“) ”,则连续出栈输出,直到遇到“( ”出栈为止(“(”只出栈,不输出);步骤③:若当前扫描元素为操作符或“(”,则将该元素的栈外优先级与栈顶元素的栈内优先级进行大小比较:若前者较小,则连续出栈输出,直到前者大于后者时,停止出栈。

此时,再将该元素进栈。

3.扫描结束,输出栈中其他元素(#除外)。

操作符# ( */ +-)ICP(外)0 7 4 2 1ISP(内)0 1 5 3 7a (/b c-)d +*e#a (/bc -)d +*e操作符# ( */ +-)ICP(外)0 7 4 2 1ISP(内)0 1 5 3 71.初始化堆栈,并将“#”进栈;2.顺序扫描中缀表达式中的每一个元素,执行如下步骤:步骤①:若当前扫描元素为操作数,则直接输出;步骤②:若当前扫描元素为“) ”,则连续出栈输出,直到遇到“( ”出栈为止(“(”只出栈,不输出);步骤③:若当前扫描元素为操作符或“(”,则将该元素的栈外优先级与栈顶元素的栈内优先级进行大小比较:若前者较小,则连续出栈输出,直到前者大于后者时,停止出栈。

C语言下表达式的自动计算(两种方式)(报告+源代码)

C语言下表达式的自动计算(两种方式)(报告+源代码)

一、设计思想第一种算法:将中缀表达式转为后缀表达式,然后通过后缀表达式计算出算术表达式的结果。

核心思想:第一步:中缀变后缀。

首先,我们做出一个统一的Node结构体,结构体内部包含四个属性,分别是操作符的字符‘op’,char类型;操作符的优先级‘level’,int 类型;数字的浮点数数值‘od’,float类型;Node的标识符,int类型。

然后,定义一个Node结构体类型的数组*listNode,这里的*listNode用的是全局变量,为了方便在得到后缀表达式后,不需再传递给计算的方法。

定义一个存放操作符的栈,遍历用户输入的算术表达式(不考虑错误情况),在遍历的过程中如果遇到数字,直接将数字存放在*listNode里面;如果遇到了操作符,则判断操作符栈目前是不是为空,如果为空,直接将遇到的操作符放入操作符栈中,如果操作符栈不为空,那么观察操作符栈中栈顶的操作符,然后再次判断当前遇到的操作符的优先级是不是比栈顶的操作符的优先级高,如果是,那么将当前的操作符入操作符栈;如果不是,那么将操作符栈的栈顶操作符取出,追加到*listNode中,然后继续观察栈顶操作符,直到当前的操作符的优先级比栈顶操作符的优先级高或者操作符栈为空时,将当前操作符入操作符栈。

如果遇到了左括号,那么定义其优先级为最低,然后直接将左括号入操作符栈。

如果遇到了右括号,那么开始从操作符栈中取出操作符追加到*listNode中,直到遇到了与之对应的左括号,然后将左括号和右括号一起销毁。

当遍历完成了算术表达式之后,这时判断操作符栈是否为空,如果不为空,那么从操作符栈中依次取出栈顶操作符追加到*listNode中,直到操作符栈为空,那么就代表我们将中缀表达式转变成为了后缀表达式。

第二步:通过得到的后缀表达式,计算算术表达式。

首先,定义一个数字栈用来存放数值。

然后,遍历*listNode中的每一个Node,如果Node是一个数字,那么就将数字入数字栈,如果Node是一个操作符,那么就从数字栈中依次取出栈顶的两个数字,然后根据操作符计算这两个数字,将得到的结果再次入数字栈,直到遍历*listNode完成,最终数字栈中会只剩下一个Node,那就是我们计算出算术表达式的结果,将结果返回给main 函数用来输出。

中缀表达式转换为后缀表达式

中缀表达式转换为后缀表达式

中缀表达式转换为后缀表达式中缀表达式转换成后缀表达式 1、概述 可以看到,后缀表达式适合计算式进⾏运算,但是⼈却不太容易写出来,尤其是表达式很长得情况下,因此在开发中,需要将中缀表达式转成后缀表达式。

2、具体步骤1.初始化两个栈:运算符栈s1和储存中间结果的栈s2;2.从左⾄右扫描中缀表达式;3.遇到操作数时,将其压s2;4.遇到运算符时,⽐较其与s1栈顶运算符的优先级: (1)如果s1为空,或栈顶运算符为左括号“(”,则直接将此运算符⼊栈; (2)否则,若优先级⽐栈顶运算符的⾼,也将运算符压⼊s1; (3)否则,将s1栈顶的运算符弹出并压⼊到s2中,再次转到(4.1)与s1中新的栈顶运算符相⽐较;5.遇到括号时: (1)如果是左括号"(",则直接压⼊s1 (2)如果是右括号")",则依次弹出s1栈顶的运算符,并压⼊s2,直到遇到左括号为⽌,此时将这⼀对括号丢弃6.重复步骤2⾄5,直到表达式的最右边7.将s1中剩余的运算符依次弹出并压⼊s28.依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式 3、案例 将中缀表达式 "1+((2+3)*4)-5" 转换为后缀表达式的过程如下: 结果为:"1 2 3 + 4 * 5 - " 4、思路分析⽰意图 5、代码实现1import java.util.ArrayList;2import java.util.List;3import java.util.Stack;45/**6 * 把中缀表达式转成后缀表达式7 *8*/9public class ToSuffixExpression {1011public static void main(String[] args) {12// 完成⼀个中缀表达式转成后缀表达式13// 说明14// 1. 1+((2+3)*4)-5 => 转成 123 + 4 * + 5-15// 2. 因为对 str进⾏操作不⽅便,先将中缀表达式存⼊ list16// 3.将得到的中缀表达式对应的 list转成 =>后缀表达式对应的list17// 即[1,+,(,(,2,+,3,),*,4,),-,5] => [1,2,3,+,4,*,+,5,-]1819 String expression = "1+((2+3)*4)-5";20 List<String> list = toInfixExpressionList(expression);21 System.out.println("中缀表达式对应的list="+list);22 List<String> list2 = parseSuffixExpressionList(list);23 System.out.println("后缀表达式对应的list="+list2);24 }2526//⽅法:将得到的中缀表达式对应的 list转成 =>后缀表达式对应的list27public static List<String> parseSuffixExpressionList(List<String> ls) {28//定义两个栈29 Stack<String> s1 = new Stack<String>(); // 符号栈3031//说明:因为 s2这个栈,在整个转换过程中,没有pop操作,后⾯还需要逆序输出 32//所以,把 s2 这个栈换成 List<String> 即可33//Stack<String> s2 = new Stack<String>(); // 存储中间结果的栈34 List<String> s2 = new ArrayList<String>(); //存储中间结果的list3536//遍历 ls37for(String item : ls) {38//如果是⼀个栈,就加⼊到s239if(item.matches("\\d+")) {40 s2.add(item);41 } else if (item.equals("(")) {42 s1.push(item);43 } else if (item.equals(")")) {44// 如果是右括号,则依次弹出s1栈顶的运算符,并压⼊ s2,知道遇到左括号为⽌,此时将这⼀对括号丢弃4546while(!s1.peek().equals("(")) {47 s2.add(s1.pop());48 }49 s1.pop(); // 将左括号弹出,消除⼩括号50 } else {51// 当 item 的优先级⼩于或等于栈顶运算符,将s1栈顶的运算符弹出并压⼊s2中,再次转到4.1与s1中新的栈顶运算符相⽐较 52//问题:缺少⽐较优先级⾼低的⽅法53while(s1.size() != 0 && Operation.getValue(s1.peek()) >= Operation.getValue(item)) {54 s2.add(s1.pop());55 }56//还需要将 item 压⼊栈中57 s1.push(item);58 }59 }6061//将s1中剩余的运算符依次弹出加⼊s262while(s1.size()!=0) {63 s2.add(s1.pop());64 }6566return s2; //因为存放到list中,因此,按顺序输出就是对应的后缀表达式对应的 list67 }686970// ⽅法:将中缀表达式转成对应的 list71public static List<String> toInfixExpressionList(String s) {72// 定义⼀个 list,存放中缀表达式对应的内容73 List<String> ls = new ArrayList<String>();74int i = 0; // 指针,⽤于遍历中缀表达式字符串75 String str; // 做对多位数的拼接⼯作76char c; // 每遍历到⼀个字符,就放⼊到 c7778do {79// 如果c是⼀个⾮数字,就需要加⼊到 ls80if ((c = s.charAt(i)) < 48 || (c = s.charAt(i)) > 57) {81 ls.add("" + c);82 i++; // i后移83 } else { // 如果是数字,考虑多位数问题84 str = ""; // 将 str置空85while (i < s.length() && (c = s.charAt(i)) >= 48 && (c = s.charAt(i)) <= 57) {86 str += c; // 拼接87 i++;88 }89 ls.add(str);90 }9192 } while (i < s.length());93return ls; // 返回94 }95 }9697/**98 * 可以返回⼀个运算符的对应的优先级99 *100*/101public class Operation {102private static int ADD = 1;103private static int SUB = 1;104private static int MUL = 2;105private static int DIV = 2;106107// 写⼀个⽅法,返回对应的优先级数字108public static int getValue(String operation) { 109int result = 0;110switch(operation) {111case "+":112 result = ADD;113break;114case "-":115 result = SUB;116break;117case "*":118 result = MUL;119break;120case "/":121 result = DIV;122break;123default:124 System.out.println("不存在该运算符"); 125break;126 }127return result;128 }129 }。

【Java数据结构】中缀表达式转后缀表达式,后缀表达式的计算(多位数)

【Java数据结构】中缀表达式转后缀表达式,后缀表达式的计算(多位数)

【Java数据结构】中缀表达式转后缀表达式,后缀表达式的计算(多位数)中缀表达式转后缀表达式,后缀表达式的计算(多位数)中缀表达式转后缀表达式思路(1)初始化两个栈stack1与stack2,分别存储数和操作符(2)从左到右扫描中缀表达式(3)遇到数字时,直接将其压⼊stack1中(4)遇到操作符时,先进性⽐较优先级,如果优先级⽐栈顶元素的⾼,则直接⼊栈如果优先级⽐栈顶元素的低,则将栈顶元素弹出压⼊数栈,再将操作符与栈顶重复⽐较,直到可以⼊栈如果符号栈为空或者栈顶是左括号(,则直接⼊栈如果操作符是右括号),则将操作符依次出栈放⼊数栈中,直到遇到左括号,⼆者直接丢弃(5)扫描完成,将操作符栈stack2依次出栈并压⼊stack1中后缀表达式计算器思路(1)初始化⼀个栈(2)遇到数字时,直接将数字压⼊栈(3)遇到运算符时,将栈顶的两个数弹出,并且计算,将结果⼊栈Java代码如下1import java.util.ArrayList;2import java.util.Deque;3import java.util.LinkedList;4import java.util.List;56public class Main {7public static void main(String[] args) {8 String str ="11+(2*4)+3*(61-1)";//结果为11+8+180=1999//将字符串转成list10 List<String> List = toInfixExpressionList(str);11 System.out.println(List);12//中缀表达式转后缀表达式13 List<String> suffixList = prefixToSuffix(List);14 System.out.println(suffixList);15//计算后缀表达式的结果16 System.out.println("后缀表达式的计算结果为:"+toCalculation(suffixList));17 }1819/**20 * 将表达式每⼀个部分转换成list21 * @param str 计算表达式22 * @return List23*/24public static List<String> toInfixExpressionList(String str){25 List<String> list = new ArrayList<>(str.length());26int i = 0;//⽤于遍历表达式的指针27char c;//⽤于存储每⼀个遍历到的字符28 StringBuilder s;//⽤于多位数的拼接29while (i<str.length()){30 c = str.charAt(i);31//如果是⾮数字,直接加⼊到list32if(c < 48 || c > 57){33 list.add(""+c);34 i++;35 }else {36 s = new StringBuilder();37while (c >= 48 && c <= 57){38 s.append(c);39 i++;40 c = str.charAt(i);41 }42 list.add(s.toString());43 }44 }45return list;46 }4748/**49 * 计算后缀表达式50 * @return计算结果51*/52public static Integer toCalculation(List<String> list){53 Deque<String> stack = new LinkedList<>();54for(String item: list){55if(isNumeric(item)){56 stack.push(item);57 }else {58int x = Integer.parseInt(stack.pop());59int y = Integer.parseInt(stack.pop());60switch (item){61case "+":62 stack.push((y+x)+"");63break;64case "-":65 stack.push((y-x)+"");66break;67case "*":68 stack.push((y*x)+"");69break;70case "/":71 stack.push((y/x)+"");72break;73default:74throw new RuntimeException("输⼊错误!");75 }76 }77 }78return Integer.parseInt(stack.pop());79 }8081/**82 * 中缀表达式转后缀表达式83 * @return List84*/85public static List<String> prefixToSuffix(List<String> list){86//初始化两个栈,stack1为数栈,stack2为操作符栈87 List<String> stack1 = new ArrayList<>();88 Deque<String> stack2 = new LinkedList<>();89for(String item: list){90if(isNumeric(item)){91//数字直接⼊栈92 stack1.add(item);93 }else if(item.equals("(")) {94//左括号或者空直接⼊栈95 stack2.push(item);96 }else if(item.equals(")")){97//右括号将符号栈中左括号前的所有符号⼊数栈98while (!stack2.peek().equals("(")){99 stack1.add(stack2.pop());100 }101 stack2.pop();//清除括号102 }else if(stack2.peek()==null||judgePriority(item)>judgePriority(stack2.peek())){ 103//优先级⽐栈顶元素⾼,直接⼊栈104 stack2.push(item);105 }else {106//优先级⽐栈顶元素低或者相等,将栈顶优先级⾼的⼊数栈107while (stack2.peek()!=null&&judgePriority(stack2.peek())<=judgePriority(item)){ 108 stack1.add(stack2.pop());109 }110 stack2.push(item);111 }112 }113while (stack2.peek()!=null){114 stack1.add(stack2.pop());115 }116117return stack1;118 }119120/**121 * 返回运算符优先级,加减为1,乘除为2122 * @param str 运算符123 * @return优先级124*/125public static int judgePriority(String str){126switch (str){127case "+":128return 1;129case "-":130return 1;131case "*":132return 2;133case "/":134return 2;135case "(":136return 0;137case ")":138return 0;139default:140throw new RuntimeException("输⼊有误!"+str); 141 }142 }143144/**145 * 判断字符串是否是正整数146 * @param str 字符串147 * @return boolean148*/149public static boolean isNumeric(String str){150for (int i = str.length();--i>=0;){151if (!Character.isDigit(str.charAt(i))){152return false;153 }154 }155return true;156 }157 }。

练手系列(3)中缀表达式转后缀表达式

练手系列(3)中缀表达式转后缀表达式

练⼿系列(3)中缀表达式转后缀表达式 最近在看数据结构和算法时,看到了中缀表达式和后缀表达式,感觉蛮有意思的,于是⾃⼰实现了⼀下,算是⼀种锻炼。

①⾸先,中缀表达式就是我们平时见惯了的算术式,⽐如:5+3这样的就是中缀表达式,⽽后缀表达式呢,就是53+这样的。

因为转为后缀表达式后,算术式的计算会相对简单⼀些,可以⽤栈来实现。

分析图如下:这种后缀表达式计算的最⼤的优点就是不⽤知道什么优先级。

②好,下⾯我们来看⼀下怎么从中缀表达式(5+3)变为后缀表达式(53+):好了,以上两张图⽚就是后缀表达式的相关分析。

下⾯上具体代码:1import java.util.Stack;23public class Calculate {4// 定义操作符号5private static final char PLUS = '+';6private static final char MINUS = '-';7private static final char MULTIPLY = '*';8private static final char DIVIDE = '/';9private static final char LEFT_PARENTHESIS = '(';10private static final char RIGHT_PARENTHESIS = ')';1112public static void main(String[] args) {13 String infix = "(3+(2-1))*5";14 String postfix = convert(infix);15 System.out.println(postfix);16 analysePostfix(postfix);17 }1819// 计算后缀表达式20public static void analysePostfix(String postfix) {21 Stack<Double> stack = new Stack<Double>();22char[] chs = postfix.toCharArray();23for (int i = 0; i < chs.length; i++) {24if (chs[i] != PLUS && chs[i] != MINUS && chs[i] != MULTIPLY25 && chs[i] != DIVIDE) {26// 如果读取到的是数字,则加到栈中27 stack.push(Double.valueOf(String.valueOf(chs[i])));28 } else {29// 如果读取到的是操作符,则从栈中弹出两个数字,并执⾏运算30double b = (double) stack.pop();31double a = (double) stack.pop();32char operator = chs[i];33double result = calculate(a, b, operator);34 stack.push(result);35 }36 }37 System.out.println("result is : " + stack.pop());38 }3940public static double calculate(double a, double b, char operator) {41switch (operator) {42case PLUS:43return a + b;44case MINUS:45return a - b;46case MULTIPLY:47return a * b;48case DIVIDE:49return a / b;50 }51return 0;52 }5354// 中缀到后缀的转换55public static String convert(String infix) {56 Stack<Character> vector = new Stack<Character>();57char[] chs = infix.toCharArray();58 StringBuffer postfix = new StringBuffer();59for (int i = 0; i < chs.length; i++) {60// 如果是数字,直接插⼊表达式中61if (chs[i] != PLUS && chs[i] != MINUS && chs[i] != MULTIPLY62 && chs[i] != DIVIDE && chs[i] != LEFT_PARENTHESIS63 && chs[i] != RIGHT_PARENTHESIS) {64 postfix.append(String.valueOf(chs[i]));65 } else {66// 如果是左括号,直接压⼊栈中67if (LEFT_PARENTHESIS == chs[i]) {68 vector.push(chs[i]);69continue;70 }71// 如果是右括號,則去除棧裏⾯的左括號之上的所有操作符號72if (RIGHT_PARENTHESIS == chs[i]) {73while (LEFT_PARENTHESIS != vector.peek()) {74 postfix.append(vector.pop());75 }76 vector.pop();77 }78// 如果当前读到的操作符和栈⾥⾯的操作符⼀样,那么直接加到后缀表达式中 79if (vector.size() > 0 && chs[i] == vector.peek()) {80 postfix.append(String.valueOf(chs[i]));81 } else if (vector.size() == 0 || chs[i] != vector.peek()) {82// 如果是乘号或者除号,直接压⼊栈中83if (MULTIPLY == chs[i] || DIVIDE == chs[i]) {84 vector.push(chs[i]);85 }86if (PLUS == chs[i] || MINUS == chs[i]) {87if (vector.size() > 088 && (vector.peek() == MULTIPLY || vector.peek() == DIVIDE)) {89 postfix.append(vector.pop().toString());90 vector.push(chs[i]);91 } else {92 vector.push(chs[i]);93 }94 }95 }96 }97// 如果已经读完了中缀表达式,则弹出栈中所有操作符并加⼊到后缀表达式中 98if (i == chs.length - 1) {99for (int j = vector.size(); j > 0; j--) {100 postfix.append(vector.pop().toString());101 }102 }103 }104return postfix.toString();105 }106 }。

C#中缀表达式转换为后缀表达式算法及后缀表达式计算算法的实现

C#中缀表达式转换为后缀表达式算法及后缀表达式计算算法的实现

/*名称:中缀表达式转换为后缀表达式算法及后缀表达式计算算法的实现内容:1、掌握栈的存储结构的C语言描述2、掌握中缀表达式转换为后缀表达式的算法实现3、掌握后缀表达式计算算法的实现要求:程序功能包括:主程序;表达式的输入、转换;后缀表达式的输出、计算和数据的输出。

名称二叉树的建立与遍历及二叉树中序线索化及线索化遍历的实现内容掌握二叉树的建立与遍历的算法实现掌握二叉树中序线索化及线索化遍历的算法实现要求程序功能包括:主程序;二叉树的建立、二叉树的遍历(前序、中序、后序)、二叉树中序线索化、线索化遍历和输出等实验报告:程序流程图;上机通过的程序(清单);总结二叉树遍历的特点*//*函数:1、线索二叉树(左孩子、右孩子、左线索标志、右线索标志、双亲、数据域)2、建立二叉树3、前、中、后序扫描二叉树4、中序线索化二叉树5、中序遍历线索二叉树6、线索二叉树查找7、线索二叉树插入功能:1、二叉树的输入实现(输入根、左、右的顺序,当左或右为空时输入0,以‘#’结束输入)(输入优化)2、前、中、后序扫描二叉树输出扫描结果3、二叉树中序线索化4、二叉树线索化遍历/*#include <stdio.h>#include <stdlib.h>#include <conio.h>#define maxsize 100typedef char datatype;typedef struct node{int ltag,rtag;datatype data;struct node *lchild,*rchild;//*parent;} bitree;bitree *root;bitree *pre;bitree *Q[maxsize];bitree *creatree(){char ch;int front,rear;//队头、队尾指针bitree *root,*s;root=NULL;//置空二叉树front=1;rear=0;//置空队列printf("\t\t>>>请输入二叉树(无孩子输入'@'并以'#'结束):\n\t\t");ch=getchar();//输入第一个字符while(ch!='#')//不是结束符时重复做{s=NULL;if(ch!='@')//@表示虚结点,不是虚结点时建立新结点{s=(bitree *)malloc(sizeof(bitree));s->data=ch;s->lchild=NULL;s->rchild=NULL;s->ltag=0;s->rtag=0;}rear++;Q[rear]=s;//将虚结点指针NULL或新结点地址入队if(rear==1) root=s;//输入的第一个结点为根结点else{if(s && Q[front])//孩子和双亲结点均不是虚结点if(rear%2==0) Q[front]->lchild=s;//rear为偶数,新结点为左孩子else //rear为奇数Q[front]->rchild=s;//新结点是右孩子if(rear%2==1) front++;//结点*Q[front]的两个孩子已经处理完毕,出队列}ch=getchar();//输入下一个字符}return root;//返回根指针}//关于建立新树:输入处理(关于完全二叉树)//中序遍历void inorder(bitree *t){if(t)//二叉树非空{inorder(t->lchild);//中序遍历t的左子树printf("%c ",t->data);//访问结点tinorder(t->rchild);//中序遍历t的右子树}}//前序遍历void preorder(bitree *t){if(t)//二叉树非空{printf("%c ",t->data);//访问结点tpreorder(t->lchild);//中序遍历t的左子树preorder(t->rchild);//中序遍历t的右子树}}//后序遍历void postorder(bitree *t){if(t)//二叉树非空{postorder(t->lchild);//中序遍历t的左子树postorder(t->rchild);//中序遍历t的右子树printf("%c ",t->data);//访问结点t}}void inthread(bitree *p)//将二叉树p中序线索化,线索标志初值为0 {if(p!=NULL){inthread(p->lchild);//左子树线索化if(p->lchild==NULL) p->ltag=1;//建立左线索标志if(p->rchild==NULL) p->rtag=1;//建立右线索标志if(pre!=NULL){if(pre->rtag==1)//p无右子树pre->rchild=p;//右线索p->rchild为pif(pre->ltag==1)//p无左子树pre->lchild=pre;//左线索p->lchild为pre}pre=p;inthread(p->rchild);//右子树线索化}}//在中序线索树中找结点*p的中序后继bitree *inordernext(bitree *p){bitree *q;if(p->rtag==1)//p右子树为空return (p->rchild);//p->rchild是右线索,指向p的后继else //p的右子树非空{q=p->rchild;//从p的右孩子开始查找while(q->ltag==0)//当q不是左下结点时,继续查找q=q->lchild;return(q);}}//遍历中序线索二叉树pvoid travereinthread(bitree *p){if(p!=NULL)//非空树{while(p->ltag==0)//找中序序列的开始结点p=p->lchild;do{printf("%c ",p->data);//访问结点pp=inordernext(p);//找p的中序后继结点}while(p!=NULL);}}void main(){bitree *p;int a=0;printf("\t\t**********************************************\n");printf("\t\t ************二叉树************\n");printf("\t\t**********************************************\n\n");p=creatree();//创建二叉树printf("\n");printf("\t\t二叉树的前序遍历结果为:\n");//前序遍历printf("\t\t"); preorder(p); printf("\n");printf("\t\t二叉树的中序遍历结果为:\n");//中序遍历printf("\t\t"); inorder(p); printf("\n");printf("\t\t二叉树的后序遍历结果为:\n");//后序遍历printf("\t\t"); postorder(p); printf("\n");inthread(p);//中序线索化printf("\t\t二叉树的中序线索化遍历结果为:\n");//后序遍历printf("\t\t");travereinthread(p);//中序线索话遍历printf("\t\t");getch();}*//*//在结点p、p的右子树之间插入新结点qinsertright(bithptr *p,bithptr *q){bithptr *s;s=inordernext(p);//查找p的原中序后继结点q->ltag=1;//建立q的左线索标志q->lchild=p;//q的中序前趋为pq->rtag=p->rtag;q->rchild=p->rchild;//q的右子树或右线索等于原p的右子树或右线索p-ratag=0;p->rchild=q;//新结点q作为p的右孩子if((s!=NULL)&&(s->ltag==1))s->lchild=q;//结点s的左链是线索,s的前趋是p}*//*#include <stdio.h>#include <stdlib.h>#include <conio.h>#include <math.h>typedef struct node//定义栈结构体类型{bool n;//标志操作数和操作符char operate;//操作符float num; //操作数struct node *next;} stack;struct changenum//临时变量{bool w;float num;char op;stack *q;} ;stack *InitStack()//初始化堆栈{stack *S;S = (stack *)malloc(sizeof(stack));S->n=0;S->num=0;S->operate=0;S->next=NULL;return S;}stack *push(stack *top,bool n,float num,char operate)//进栈函数{stack *p;p=(stack *)malloc(sizeof(stack));//生成新节点if(n==0)//进栈的为浮点数{p->n=0;p->operate=NULL;p->num=num;}if(n==1)//进栈的为操作符{p->n=1;p->operate=operate;p->num=NULL;}p->next=top;top=p;return p;}changenum *pop(stack *top)//退栈函数{stack *p;changenum *sp;sp=(changenum *)malloc(sizeof(changenum));if(top->next==NULL) {printf("underflow!\n");return NULL;}//栈下溢else//退栈操作{p=top;top=top->next;sp->q=top;sp->num=p->num;sp->op=p->operate;sp->w=0;return sp;}}//*******************************************//****************栈定义及操作***************//后缀表达式的存储//*******************************************typedef struct node2{bool n;//标志操作数和操作符float num;//操作数char operate;//操作符struct node2 *front,*rear,*next;//队头队尾指针} squeue; //定义队列类型squeue *q;squeue *InitQueue()//初始化队列{squeue *Q;Q = (squeue *)malloc(sizeof (squeue));Q->n=0;Q->front=Q;Q->num=12345;Q->operate=0;Q->front->next=NULL;Q->rear =Q;return Q;}void enqueue(squeue *q,bool n,float number,char op)//入队操作{if(op==')') ;else{q->rear->next=(squeue *)malloc(sizeof(squeue));q->rear=q->rear->next;if(n==0){q->rear->n=0;q->rear->operate=NULL;q->rear->num=number;}if(n==1){q->rear->n=1;q->rear->operate=op;q->rear->num=NULL;}q->rear->next=NULL;}}changenum *dequeue(squeue *q)//出队操作{squeue *s;changenum *sp;sp=(changenum *)malloc(sizeof(changenum));if(q->front->next==NULL) {sp->num=q->num;sp->w=q->n;} else{s=q->front->next;q->front->next=s->next;sp->w=s->n;sp->num=s->num;sp->op=s->operate;}return sp;}//*******************************************//****************队定义及操作***************//实现表达式的临时存储//*******************************************int priority(char ch)//操作符及操作数优先级判断{switch(ch){case'+': case'-': return 2;case'*': case'/':return 3;case'(': case'#': return 1;case')': return 4;case ' ':return 10;case'.': case'0': case'1': case'2':case'3': case'4': case'5': case'6':case'7': case'8': case'9': return 0;default:printf("ERROR!"); return 5;}}changenum *getlist(char ch)//将字符数组转为float类型变量{changenum *sp;sp=(changenum *)malloc(sizeof(changenum));if(priority(ch)==0){sp->w=0;int p=1;float sum=0,point=0;char a[40];int m=0;int n=1;for(int i=0;i<=39;i++)a[i]=0;while(ch!='.'&&priority(ch)==0){a[m]=ch; sum=sum*10+(a[m]-'0'); m++;//整数部分ch=getchar();}if(ch=='.'){ch=getchar();while(priority(ch)==0)//小数部分处理{a[m+n]=ch; point=point*10+(a[m+n]-'0');p=p*10; n++;ch=getchar();}}sum=sum+point/p;//转为浮点数sp->num=sum;sp->op=ch;return sp;}else{sp->w=1;sp->num=100;sp->op=100;return sp;}}float change()//输入中缀表达式并转换为后缀表达式、输出后缀表达式并计算结果{stack *formula1;squeue *formula2,*formula4;stack *formula3;char a,ch;bool i; changenum *mark,*sign;formula2=InitQueue();formula4=InitQueue();formula1=InitStack();formula3=InitStack();formula3=push(formula3,1,0,'#');formula1=push(formula1,1,0,'#');printf("请输入表达式以#结束:\n");ch=getchar();do{mark=getlist(ch);i=mark->w;if(i==0){enqueue(formula2,0,mark->num,0);enqueue(formula4,0,mark->num,0);ch=mark->op;free(mark);/ /将操作数入队}else{switch(ch)//操作符处理{case '(' : formula1=push(formula1,1,0,ch); break; //将做括号压入栈Scase ')' :if(formula1->operate=='#') {printf("括号不匹配!!!\n");return 1;}else{do{sign=pop(formula1);formula1=sign->q;a=sign->op;if(a=='(') break;else if(priority(a)==4) ;else{enqueue(formula2,1,0,a);enqueue(formula4,1,0,a);}}while(a!='#');if(a=='#') {printf("括号不匹配!!!\n");return 1;}}case '+' :case '-' :case '*' :case '/' :while (formula1->operate!='#' && formula1->operate!='(' && priority(formula1->operate)>=priority(ch)){sign=pop(formula1);formula1=sign->q;enqueue(formula2,1,0,sign->op);enqueue(formula4,1,0, sign->op);}formula1=push(formula1,1,0,ch);break;case '#' : break;default: printf("ERROR!!!\n");return 1;}ch=getchar();}}while(ch!='#');//表达式扫描结束条件//表达式扫描结束后若栈中还有元素则依次弹出输入的后缀表达式中while (formula1->operate!='#'){sign=pop(formula1);formula1=sign->q;if(sign->op=='(') {printf("括号不匹配!!!\n");return 1;}else {enqueue(formula2,1,0,sign->op);enqueue(formula4,1,0,sign->op);}}printf("后缀表达式为:\n");do//后缀表达式的输出{mark=dequeue(formula2);if(mark->num==12345) break;if(mark->w==0){printf("%.3f",mark->num);free(mark);}else{printf("%c",mark->op);free(mark);}}while(1);printf("\n");/////////////////////////////////////////////////////////后缀表达式的计算////////////////////////////////////////////////////////float x,y;mark=dequeue(formula4);while (mark->num!=12345)//若队不为空{if (mark->w==0){formula3=push(formula3,0,mark->num,0);free(mark);}else{sign=pop(formula3);y =sign->num; formula3=sign->q;free(sign);//两次取操作数并交换次序sign=pop(formula3);x =sign->num; formula3=sign->q;free(sign);switch (mark->op)//计算周缀表达式的值{case '+' : formula3=push(formula3,0, x + y,0);break;case '-' : formula3=push(formula3,0, x - y,0);break;case '*' : formula3=push(formula3,0, x * y,0);break;case '/' : formula3=push(formula3,0, x / y,0);break;default:printf("ERROR!!!\n");return 0;}}mark = dequeue(formula4);//出队操作}printf("表达式的计算结果为:%.3f\n",pop(formula3)->num);return 0;}void main(){float sum;bool a;sum=change();//计算并转换后缀表达式getch();}*/。

中缀表达式转化为后缀表达式算法

中缀表达式转化为后缀表达式算法

中缀表达式转化为后缀表达式算法首先需要分配2个栈,一个作为临时存储运算符的栈S1(含一个结束符号),一个作为输入后缀表达式的栈S2(空栈),S1栈可先放入优先级最低的运算符#,注意,中缀式应以此最低优先级的运算符结束。

可指定其他字符,不一定非#不可。

从中缀式的左端开始取字符,逐序进行如下步骤:(1)若取出的字符是数字,则分析出完整的运算数,该运算数直接送入S2栈(2)若取出的字符是运算符,则将该运算符与S1栈栈顶元素比较,如果该运算符优先级大于S1栈栈顶运算符优先级,则将该运算符进S1栈,否者,将S1栈的栈顶运算符弹出,送入S2栈中,直至S1栈栈顶运算符低于(不包括等于)该运算符优先级,则将该运算符送入S1栈。

(3)若取出的字符是“(”,则直接送入S1栈栈顶。

(4)若取出的字符是“)”,则将距离S1栈栈顶最近的“(”之间的运算符,逐个出栈,依次送入S2栈,此时抛弃“(”。

(5)重复上面的1~4步,直至处理完所有的输入字符(6)若取出的字符是“#”,则将S1栈内所有运算符(不包括“#”),逐个出栈,依次送入S2栈。

完成以上步骤,S2栈便为后缀表达式输出结果。

不过S2应做一下逆序处理。

便可以按照后缀表达式的计算方法计算了!做法如下将该字符与运算符栈顶的运算符的优先关系相比较。

如果,该字符优先关系高于此运算符栈顶的运算符,则将该运算符入栈。

倘若不是的话,则将栈顶的运算符从栈中弹出,直到栈顶运算符的优先级低于当前运算符,将该字符入栈。

(5)重复上述操作(1)-(2)直至扫描完整个简单算术表达式,确定所有字符都得到正确处理,我们便可以将中缀式表示的简单算术表达式转化为逆波兰表示的简单算术表达式。

后缀表达式的作用对于实现后缀表达式算法,难度并不大,但为什么要将看似简单的中缀表达式转换为复杂的后缀表达式?原因就在于这个简单是相对人类的思维结构来说的,对计算机而言中缀表达式是非常复杂的结构。

相对的,后缀表达式在计算机看来却是比较简单易懂的结构。

中缀表达式变后缀表达式算法

中缀表达式变后缀表达式算法

❖ Postfix(&s,strcat(expression,“#”)); ❖}
❖ printf(“% c”,x); ❖ if((x1=gettopqstack(s))==NIL) ❖ exit(0); ❖} ❖ else if(proceed(x1,x2)==‘=‘&& x1=‘(‘ &&
x2=‘)’) ❖ { if(popqstack(s)==NIL) ❖ exit(0); ❖ if((x1=gettopqstack(s))==NIL) ❖ exit(0);
❖ Return result; ❖} ❖ 主函数如下: ❖ #include <stdio.h> ❖ #include <string.h> ❖ #include<stdlib.h> ❖ #define MAXNUM 100 ❖ #define NIL 0
❖ typedef char elemtype;
❖ elemtype gettopqstack(qstype *s); ❖ char proceed(char x1,char x2); ❖ Int postfix(qstype *s,char *expression); ❖ main() ❖{ ❖ char expression[80]={“A+(B-C/D)*E”}; ❖ qstype s; ❖ printf(“\n”);
❖ If((x1=gettopqstack(s))==NIL) ❖ exit(0); ❖ while(1) ❖{ ❖ if(x2!=‘+’&& x2!=‘-’&& x2!=‘*’&&
x2!=‘/’&& x2!=‘(‘ && x2!=‘)’ && x2!=‘#’) ❖ { printf(“% c”,x2); ❖ x2=expression[++j]; ❖}

中缀表达式转化成后缀表达式的计算

中缀表达式转化成后缀表达式的计算

目录一、设计思想 (01)二、算法流程图 (02)三、源代码 (03)四、运行结果 (16)五、遇到的问题及解决 (17)六、心得体会 (18)一、设计思想第一种算法先把算术表达式转化成后缀表达式,在对后缀表达式进行计算。

首先建立一个符号栈,用于存放字符和字符的优先级别;然后在建立一个数栈,用于辅助后缀表达式的计算;最后在定义一个字符串数组,用于存放后缀表达式。

建立一个计算的函数,该函数用于两个数的计算,在调用这个函数的时候,传入三个参数,两个浮点型参数和一个字符型参数,根据不同的符号进行不同的计算。

定义一个判断优先级别的函数,用于判断两个操作符的优先级别,在根据优先级的不同决定不同的操作。

后缀表达式的取得,对算术表达式字符串进行挨个的扫描,如果是数字或者是小数点,则将数字或者小数点存放到字符数组中,每取完一个数字,则在后面用“|”隔开,如果是操作符,则和栈中得操作符进行比较,若扫描到的符号优先级比栈里的符号优先级低,则栈中元素出栈并存放到字符数组中。

每出一个字符到字符数组中就在后面加“|”分隔。

继续检查栈顶比较优先级,直到栈中元素优先级比扫描到的符号优先级低或者符号栈为空,则将此操作符入栈。

若是“(”则无条件入字符栈,若是“)”则从字符栈中出字符直到遇到“(”为止。

当字符数组扫描到最后的时候,计算并没有结束。

然后得进行字符栈的判断,看是否已经为空栈,若不是空栈,则出栈字符,将字符存放到数组中。

最后字符串数组中存放的就是后缀表达式。

得到后缀表达式后,要用数栈进行后缀表达式的计算,后缀表达式的计算中,对新的数组进行从道到尾的扫描,如果遇到数字,以“|”为标记取出完整的操作数,用辅助数组存放,然后转化成浮点数存放到数栈中,遇到“|”则直接将数组下标往后走。

遇到字符,则从数栈取出两个数进行计算,将计算的结果从新存放到数栈中,循环直到接到结束。

最后存放在数栈中的数就是计算的结果。

最后在主函数中调用此函数,进行结果的输出。

中缀表达式转后缀表达式(代码实现)及前缀表达式思路补充

中缀表达式转后缀表达式(代码实现)及前缀表达式思路补充

中缀表达式转后缀表达式(代码实现)及前缀表达式思路补充 后缀表达式适合计算机式的计算,因此在开发中,我们需要将中缀表达式转为后缀表达式。

三种表达式 这⾥再次区分⼀下前缀表达式、中缀表达式、后缀表达式(以(3+4)*5-6为例) 中缀表达式就是我们正常遇见的(3+4)*5-6这样的式⼦ 前缀表达式⼜称为波兰式,其运算符是在数之前 中缀表达式转前缀表达式思路:从右⾄左扫描表达式,遇到数字时,将数字压⼊堆栈,遇到运算符时,弹出栈顶的两个数,⽤运算符对它们做相应的计算(栈顶元素 top 次顶元素),并将结果⼊栈;重复上述过程直到表达式最左端,最后运算得出的值即为表达式的结果 例如:- * + 3 4 5 61. 从右⾄左扫描,将6、5、4、3压⼊堆栈2. 遇到+运算符,因此弹出3和4(3为栈顶元素,4为次顶元素,注意与后缀表达式做⽐较),计算出3+4的值,得7,再将7⼊栈3. 接下来是×运算符,因此弹出7和5,计算出7×5=35,将35⼊栈4. 最后是-运算符,计算出35-6的值,即29,由此得出最终结果中缀表达式转后缀表达式具体步骤 1).初始化两个栈:运算符栈s1和存储中间结果的栈s2; 2).从左到右扫描中缀表达式; 3).遇到操作数时,将其压⼊s2; 4).遇到运算符时,⽐较其与s1栈顶运算符的优先级; 1.如果s1为空,或栈顶运算符为左括号"(",则直接将此运算符⼊栈 2.否则,若优先级⽐栈顶运算符的⾼,也将运算符压⼊s1 3.否则,将s1栈顶的运算符弹出并压⼊s2中,再次转到(4-1)与s1中新的栈顶运算符相⽐较; 5)遇到括号时: (1)如果时左括号"(",则直接压⼊s1 (2)如果是右括号")",则依次弹出s1栈顶的运算符,并压⼊s2,直到遇到左括号为⽌,此时将这⼀对括号丢弃 6)重复2⾄5,直到表达式的最右边 7)将s1中剩余的运算符依次弹出并压⼊s2 8)依次弹出s2中的元素并输出,结果的逆序为中缀表达式对应的后缀表达式举例说明 将中缀表达式"1+((2+3)*4)-5"转换为后缀表达式为:"1 2 3 + 4 * + 5 -"过程如下:举例代码package com.atxihua;import java.util.ArrayList;import java.util.List;import java.util.Stack;public class PolandNotation1 {public static void main(String[] args) {//完成将⼀个中缀表达式转成后缀表达式的功能//1+((2+3)*4)-5转成1 2 3 + 4 * + 5 -//因为直接对str进⾏操作,不⽅便,因此,先将1+((2+3)*4)-5存⼊对应的list//即1+((2+3)*4)-5=》ArrayList[1,+,(,(,2,+,3,),*,4),-,5]//将得到的中缀表达式对应的List=》后缀表达式对应的List//即ArrayList[1,+,(,(,2,+,3,),*,4),-,5]=>ArrayList[1,2,3,+,4,*,+,5,-]String expression="1+((2+3)*4)-5";List<String> infixExpreesionList=toInfixExpreesionList(expression);System.out.println("中缀表达式="+infixExpreesionList);//ArrayList[1,+,(,(,2,+,3,),*,4),-,5] List<String> suffixExpreesionList=parseSuffixExpreesionList(infixExpreesionList);System.out.println("后缀表达式="+suffixExpreesionList);//ArrayList[1,2,3,+,4,*,+,5,-]System.out.println("结果为:"+calculate(suffixExpreesionList));}//将中缀表达式转成对应的listprivate static List<String> toInfixExpreesionList(String s) {//定义⼀个List,存放中缀表达式对应的内容List<String> ls=new ArrayList<String>();int i=0;//⽤于遍历中缀表达式字符串String str;//⽤于拼接多位数char c;//每遍历到⼀个字符,就放到cdo{//如果c是⼀个⾮数字,我们需要加⼊到lsif((c=s.charAt(i))<48||(c=s.charAt(i))>57){ls.add(""+c);i++;}else {//如果是⼀个数,需要考虑多位数str="";//先将str设置为0[48]-9[57]while (i<s.length()&&(c=s.charAt(i))>=48&&(c=s.charAt(i))<=57){str+=c;//拼接i++;}ls.add(str);}}while (i<s.length());return ls;}//将得到的中缀表达式对应的List=>后缀表达式private static List<String> parseSuffixExpreesionList(List<String> ls) {//定义两个栈Stack<String> s1=new Stack<String>();//符号栈//说明:s2这个栈,在整个转换过程中,没有pop操作,⽽且后⾯需要逆序输出,就不使⽤栈,直接使⽤list存储//Stack<String> s2=new Stack<String>();//数栈List<String> s2=new ArrayList<String>();//存储中间结果的list//遍历lsfor(String item:ls){//如果是⼀个数,加⼊s2if(item.matches("\\d+")){s2.add(item);}else if(item.equals("(")){s1.push(item);}else if(item.equals(")")){//如果是右括号")",则依次弹出s1栈顶的运算符,并压⼊s2,直到遇到左括号为⽌,此时,将这⼀对括号丢弃while (!s1.peek().equals("(")){s2.add(s1.pop());}s1.pop();//将 ( 弹出s1栈,消除⼩括号}else {//当item的优先级⼩于等于s1栈顶运算符,将s1栈顶运算符弹出并加⼊到s2,直到遇到左括号为⽌,此时将这⼀对括号丢弃 //我们缺少⼀个⽐较优先级⾼低的⽅法while (s1.size()!=0&& Operation.getValue(s1.peek())>=Operation.getValue(item)){s2.add(s1.pop());}//还需要将item压⼊栈s1.push(item);}}//将s1中剩余的运算符依次弹出并加⼊s2while (s1.size()!=0){s2.add(s1.pop());}return s2;//}private static int calculate(List<String> ls) {//创建⼀个栈Stack<String> stack = new Stack<String>();//遍历lsfor(String item:ls){//使⽤正则表达式来取数if(item.matches("\\d+")){//匹配多为数//⼊栈stack.push(item);}else {//pop出两个数并运算,再⼊栈int num2=Integer.parseInt(stack.pop());int num1=Integer.parseInt(stack.pop());int res=0;if(item.equals("+")){res=num1+num2;}else if(item.equals("-")){//注意num2⽐num1先出栈,所以是num1-num2res=num1-num2;}else if(item.equals("/")){res=num1/num2;}else if(item.equals("*")){res= num1*num2;}else {throw new RuntimeException("运算符有误");}//把res⼊栈stack.push(""+res);}}//最后留在stack中的数据即运算结果return Integer.parseInt(stack.pop());}}//编写⼀个类Operation可以返回⼀个运算符,对应的优先级class Operation{private static int Add=1;private static int SUB=1;private static int MUL=2;private static int DIV=2;//写⼀个⽅法,返回对应的优先级数字public static int getValue(String operation){int result=0;if(operation.equals("+")){result=Add;}else if(operation.equals("-")){result=SUB;}else if(operation.equals("*")){result=MUL;}else if(operation.equals("/")){result=DIV;}else {System.out.println("不存在该运算符");}return result;}}运⾏结果因为我们在写代码时,遇到左括号时,压⼊栈中,在遇到右括号时在处理,因此,计算机将左括号当作运算符处理,在处理逻辑中只对加减乘除进⾏了处理,相信这点很容易理解,就不再处理了。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

❖lf((x1=gettopqstack(s))==NIL) ・:・exit(O);
❖while(1)
•if(x2!='+'&& x2!='・'&& x2!=*&&
x2!=7'&& x2!=t(t && x2!=')' && x2!='#') •{ printf("% c",x2);
•x2=expression[++j];
•:・)
・:♦else if(proceed(x1,x2)==t<t) ・:・{if(!pushqstack(s,x2))
・:・e xit(O);
・:・if((x1=gettopqstack(s))==NIL) ・:・e xit(O);
♦x2= expression[++j];
•:・)
♦else if(proceed(x1,x2)==t>t)
♦{if((x=popqstack(s))==NIL)
・:・exit(O);
❖printf("%c”,x);
❖if((x1 =gettopqstack(s))==NIL)
・:・exit(O);
.:・}
❖else if(proceed(x1 ,x2)==-{&& x仁'('&& x2=')')
❖{if(popqstack(s)==NIL)
・:・exit(O);
❖if((x1 =gettopqstack(s))==NIL)
・:・exit(O);
•x2= expression[++j];
.:・}
•else if(proceed(x1 ,x2)==-c&& x仁# && x2=#)
•{ return 1;
.:・)
•else if(proceed(x1,x2)==c')
•break;
・:・}
•Printf(An错误!” );
•return 0;
•:・proceed(x1,x2)完成算符比较功能•char proceed(char x1 ,char x2)
❖Midstring[0]=x2;
・:・midstring[1]=t\0,;
•:・if(((x1=='+'||x1='・')&&strstr("+・)#,,,midstring)!=NULL||
((x1=*||x 仁'/')&&strstr("+・*/)#”,midstring)!=NULL)
||(x1 ==')')&&strstr("+・
*/)#”,midstring)!=NULL)) .:・{
❖result。

';
❖Else if((x1==t&&x2==y)|| ❖(x1==*&& x2=#))・:.{
❖result—;
.:・)
❖Else if((x1 ='('&& x2==#)|| ❖(x1==t),&& x2=t(,)|| •:・(x1==t#,&&x2==t)>)) ❖{ result^'
❖Return result;
.:・}
•:•主函数如下:
"include <stdio.h>
❖#include <string.h>
❖#include<stdlib.h>
❖#define MAXNUM 100
❖#define NIL 0
• typedef char elemtype; •Typedef struct
.:・{
・:・elemtype stack[MAXNUM]; •int top;
•)qstype;
❖elemtype gettopqstack(qstype *s);
❖char proceed(char x1 ,char x2);
❖Int postfix(qstype *s,char ^expression); ❖main()
・:.{
❖char expression[80]={tt A+(B-C/D)*E,}; ❖qstype s;
❖printf(t,\n,^);
• Postfix(&s,strcat(expression,"#"));
・:.}
•char result;
•char midstring[2];
•result*’;
•void initiateqstack(qstype *s);
•int pushqstack(qstype*s,elemtype x); •elemtype popqstack(qstype *s);。

相关文档
最新文档