中缀表达式转后缀表达式并计算结果(C语言版)
将中缀表达式转换为后缀表达式C程序

5 将中缀表达式转换为后缀表达式【问题描述】表达式转换。
输入的中缀表达式为字符串,转换得到的后缀表达式存入字符数组中并输出。
例如:a*(x+y)/(b-x) 转换后得:a x y + * b x - /【数据结构】●定义一个暂时存放运算符的转换工作栈opst。
●中缀表达式字符串char *infix;●后缀表达式字符串char *postfix;【算法提示】转换规则:把运算符移到它的两个操作数后面,删除掉所有的括号。
从头到尾扫描中缀表达式,对不同类型的字符按不同情况处理:●数字或小数点,直接写入字符串postfix,并在每个数值后面写入一个空格;●左括号,进栈,直到遇见相配的右括号,才出栈;●右括号,表明已扫描过括号内的中缀表达式,把从栈顶直到对应左括号之间的运算符依次退栈,并把结果推入栈内;●对于运算符,分两种情况处理:◆该运算符的优先级大于栈顶符号的优先级,则入栈;◆若该运算符的优先级小于栈顶优先级,则先弹出栈顶运算符、写入postfix串;继续将该运算符与栈顶运算符比较,直到能把它推入栈内为止(即优先级大于栈顶运算符)。
说明:自行设计运算符优先级的表示。
【主要代码】#include<iostream.h>#include<assert.h>#include<math.h>#include<string.h>const int stackIncreament=0;class opst{public:opst(int sz=50){maxSize=sz;top=-1;elements=new char[maxSize];assert(elements!=NULL);}~opst(){delete[]elements;}bool IsEmpty(){return (top==-1)?true:false;} bool IsFull(){return(top==maxSize-1)?true:false;}void Push( char &x);bool Pop(char &x);bool getTop(char &x);int getSize()const{return top+1;}void MakeEmpty(){top=-1;}void input();void Convert();friend ostream& operator<<(ostream &os,opst &s);private:char *elements;int top;int maxSize;void overflowProcess();};void opst::overflowProcess()//溢出处理{char *newArray=newchar[maxSize+stackIncreament];for(int i=0;i<=top;i++)newArray[i]=elements[i];maxSize=maxSize+stackIncreament; delete [] elements;elements=newArray;}void opst::Push(char &x){if(IsFull()==true) overflowProcess(); elements[++top]=x;}bool opst::Pop( char &x){if(IsEmpty()==true) return false;x=elements[top--];return true;}bool opst::getTop(char &x){if(IsEmpty()==true)return false;x=elements[top];return true;}ostream& operator<<(ostream &os,opst &s) {os<<"top=="<<s.top<<endl;for(int i=0;i<=s.top;i++)os<<s.elements[i];return os;}void opst::input(){char ch[20];cout<<"请输入中缀表达式(括号不能省略):"<<endl;cin.getline(ch,20);int i=0;while(ch[i]!='\0'){this->Push(ch[i]);i++;}ch[i]='#';}bool isdigit(char &x){if((x>='a'&&x<='z')||(x>='A'&&x<='Z')||(x>=' 0'&&x<='9'))return true;else return false;}int isp(char &x)//设置栈内优先级{switch(x){case '#':{return 0;break;}case '(':{return 1;break;}case '*':case '/':case '%':{return 5;break;}case '+':case '-':{return 3;break;}case ')':{return 6;break;}}}int icp(char &x)//设置栈外优先级{switch(x){case '#':{return 0;break;}case '(':{return 6;break;}case '*':case '/':case '%':{return 4;break;}case '+':case '-':{return 2;break;}case ')':{return 1;break;}}}void opst::Convert(){opst s;int i=0;char ch='#',ch1,op;s.Push(ch);this->Push(ch);elements[i];while(this->IsEmpty()==false&&elements[i]! ='#'){if(isdigit(elements[i])){cout<<elements[i];i++;}else{s.getTop(ch1);if(isp(ch1)<icp(elements[i])){s.Push(elements[i]);i++;}else if(isp(ch1)>icp(elements[i])){s.Pop(op);cout<<op;}else{s.Pop(op);if(op=='(') i++;}}}}void main(){opst a;a.input();cout<<"后缀表达式为:"<<endl;a.Convert();cout<<endl;}【实验过程】请输入中缀表达式(括号不能省略):(a+((b-c)/d))后缀表达式为:abc-d/+【实验体会】怎么样设置栈内外的优先级是解决这个程序的关键,我是用了开关语句来实现的。
中缀表达式转换为后缀表达式_数据结构(C语言)_[共2页]
![中缀表达式转换为后缀表达式_数据结构(C语言)_[共2页]](https://img.taocdn.com/s3/m/9ea96295a8956bec0875e32d.png)
第3章堆栈和队列39 c=getchar();}if(Top(S, &newop))printf("%f", newop); //取栈顶元素,得结果输出Destroy(S); //释放堆栈创建时动态申请的空间}若输入的后缀表达式为6 4 2 − / 3 2 * +,则计算结果为9。
设后缀中的符号数为n(表达式中操作数、操作符和界限符的总数)。
不难看出,函数GetOperands()和DoOperator()的时间复杂度均为O(1)。
主函数main()对输入的表达式只进行一次扫描,所以其时间复杂度为O(n)。
3.3.3 中缀表达式转换为后缀表达式由于后缀表达式具有计算简便等优点,编译程序中常将中缀表达式转换为后缀表达式。
这种转换也是栈应用的一个典型例子。
从表3.2中可以看出,在中缀和后缀两种形式中,操作数的顺序是相同的。
因此很容易得到转换过程:(1)从左到右逐个扫描中缀表达式中各项,遇到结束符“#”转(6),否则继续;(2)遇到操作数直接输出;(3)若遇到右括号“)”,则连续出栈输出,直至遇到左括号“(”为止(注意:左括号出栈但并不输出),否则继续;(4)若是其他操作符,则和栈顶的操作符比较优先级,若小于等于栈顶操作符的优先级,则连续出栈输出,直到大于栈顶操作符的优先级结束,操作符进栈;(5)转(1)继续;(6)输出栈中剩余操作符(#除外)。
实现这个转换的关键是确定操作符的优先级,因为优先级决定了操作符是否进、出栈。
操作符在栈内外的优先级应该有所不同,以体现中缀表达式同优先级操作符从左到右的计算要求。
左括号的优先级在栈外最高,但进栈后应该比除“#”外的操作符低,可使括号内的其他操作符进栈。
为此,设计了栈内优先级isp(in-stack priority)和栈外优先级icp(incoming priority),如表3.4所示。
表3.4 操作符的栈内外优先级表3.5所示为中缀表达式a/(b−c)+d*e转换为后缀表达式abc−/de*+的方法。
c语言实现中缀、后缀、前缀表达式相互转化并求值

1.问题描述(1)表达式求值问题表达式是数据运算的基本形式。
人们的书写习惯是中缀式,如:11+22*(7-4)/3 。
中缀式的计算按运算符的优先级及括号优先的原则,相同级别从左到右进行计算。
表达式还有后缀式(如:2274-*3/11+)和前缀式(如: + 11 / * 22–7 4 3)。
后缀表达式和前缀表达式中没有括号,给计算带来方便。
如后缀式计算时按运算符出现的先后进行计算。
本设计的主要任务是进行表达式形式的变换及不相同形式的表达式计算。
2.数据结构设计( 1)表达式求值问题由于表达式中有字符与数字两各种类,故定义结点一个标志域 data ,标志结点储藏的为字符 data=2 还是数字 data=1 ,再搜寻结点中对应的储藏地址,读取数字域 data1, 字符域 data2 。
而在前缀表达式时,存在表达式逆序,因表达式种类不一致,用栈逆序极不方便,选择成立双向链表,储藏表达式。
typedef struct Node//定义储藏中缀表达式的结点种类{int data;int data1;char data2;struct Node *next;}Lnode;typedef struct Node2//定义储藏前缀表达式的结点种类{int data;int data1;char data2;struct Node2 *next;struct Node2 *prior;}Lnode2;3. 运行、测试与解析( 1)表达式求值问题(1)按提示输入中缀表达式,以下列图。
如输入中缀表达式不正确,提示输入有误,如图 , 所示。
图图图(2)选择表达式变换并求值方式。
按“1”选择中缀表达式求值,以下列图。
图(3)按“ 2”选择中缀表达式转变为后缀表达式并求值,以下列图。
图(4)按“ 3”选择中缀表达式转变为前缀表达式并求值,以下列图。
图附录:源代码( 1)表达式求值问题#include<>#include<>#define MAXNUM 100typedef struct Node//定义储藏中缀表达式的结点种类{int data;int data1;char data2;struct Node *next;}Lnode;typedef struct Node2//定义储藏前缀表达式的结点种类{int data;int data1;char data2;struct Node2 *next;struct Node2 *prior;}Lnode2;typedef int selemtype1;//定义运算数栈的结点typedef struct //定义运算数栈的种类{selemtype1 *base;selemtype1*top; }sqstack1;void InitStack1(sqstack1 &s) //新建一个空运算数栈{=(selemtype1 *)malloc(MAXNUM*sizeof(selemtype1));=;if(! printf("出错:申请空间失败!\n");}void Push1(sqstack1 &s,selemtype1 &e)//运算数栈,入栈:插入元素 e 为新的栈顶元素{ if printf("出错:表达式过长!1\n");*++=e;}void GetTop1(sqstack1 s,selemtype1 &e) //运算数栈,用e返回栈顶元素{e=*;}void Popopnd1(sqstack1 &s,selemtype1 &e) // 运算数栈,退栈:删除栈顶元素,并用 e 返回其值{e=*;}int stackempy1(sqstack1 s) // 运算数栈,若为空栈返回 1,否则返回 0 {if== return 1;else return 0;}typedef char selemtype2;//定义运算符栈的结点种类typedef struct //定义运算符栈种类{selemtype2 *base;selemtype2*top; }sqstack2;void InitStack2(sqstack2 &s) //新建一个空运算符栈{=(selemtype2 *)malloc(MAXNUM*sizeof(selemtype2));=;if(! printf("出错:申请空间失败!\n");}void Push2(sqstack2 &s,selemtype2 &e)//运算符栈,入栈:插入元素 e 为新的栈顶元素{ if printf("出错:表达式过长!2\n");*++=e;}void GetTop2(sqstack2 s,selemtype2 &e) //运算符栈,用e返回栈顶元素{e=*;}void Popopnd2(sqstack2 &s,selemtype2 &e) // 运算符栈,退栈:删除栈顶元素,并用 e 返回其值{e=*;}int stackempy2(sqstack2 s) // 运算符栈,若为空栈返回 1,否则返回 0 {if== return 1;else return 0;}void priority(char c,int &i)//确定运算符优先级{if (c=='*'||c=='/'||c=='%') i=2 ;else if (c=='+'||c=='-') i=1 ;else i=0;}int compare(char a,char b) //比较栈顶元素运算符与外面运算符优先级大小,外面优先级大则返回1,反之返回 0{int in,out;priority(a,in);priority(b,out);if(out>in) return 1;else return 0;}void Operat(sqstack1 &OPND,sqstack2 &OPTR){int num1,num2,num;char c;Popopnd1(OPND,num2);Popopnd1(OPND,num1);Popopnd2(OPTR,c);switch(c){case '+':num=num1+num2;break;case '-':num=num1-num2;break;case '*':num=num1*num2;break;case '/':num=num1/num2;break;case '%':num=num1%num2;break;}Push1(OPND,num);}void Operatqianzhui(sqstack1 &OPND,sqstack2 &OPTR){int num1,num2,num;char c;Popopnd1(OPND,num1);Popopnd1(OPND,num2);Popopnd2(OPTR,c);switch(c){case '+':num=num1+num2;break;case '-':num=num1-num2;break;case '*':num=num1*num2;break;case '/':num=num1/num2;break;case '%':num=num1%num2;break;}Push1(OPND,num);}//后缀表达式求值void houzhuiqiuzhi(Lnode *p,int &e){sqstack1 OPND; //运算数栈sqstack2 OPTR; //运算符栈int n;char c;p=p->next;InitStack1(OPND);InitStack2(OPTR);while(p){switch(p->data){case 1:n=p->data1;Push1(OPND,n);break;case 2:c=p->data2;Push2(OPTR,c);Operat(OPND,OPTR);break;default:printf("结点有误 ");break;}p=p->next;}Popopnd1(OPND,n);e=n;}void zhongzhui(Lnode *p)//中缀表达式求值{sqstack1 OPND; //运算数栈sqstack2 OPTR; //运算符栈int n;char c,c2;Lnode *first;first=p;p=p->next;InitStack1(OPND);InitStack2(OPTR);while(!stackempy2(OPTR)||p){while(p){switch(p->data){case 1:n=p->data1;Push1(OPND,n);break;case 2:c=p->data2;if(stackempy2(OPTR)) Push2(OPTR,c);else { switch(c){case '(': Push2(OPTR,c);break;case ')': GetTop2(OPTR,c2);while(c2!='('){Operat(OPND,OPTR);GetTop2(OPTR,c2);}Popopnd2(OPTR,c2);break;default: GetTop2(OPTR,c2);if(compare(c2,c)) Push2(OPTR,c);else { Operat(OPND,OPTR);Push2(OPTR,c);}break;}}break;default: printf("结点有误");break;}p=p->next;}while(!stackempy2(OPTR))Operat(OPND,OPTR);}Popopnd1(OPND,n);p=first->next;while(p){if(p->data==1) printf("%d ",p->data1);if(p->data==2) printf("%c",p->data2);p=p->next;}printf("=%d ",n);}void houzhui(Lnode*p)//中缀表达式转变为后缀表达式{sqstack2 OPTR; //运算符栈Lnode *r,*q,*head;int n;char c,c2;InitStack2(OPTR);p=p->next;q=(Lnode*)malloc(sizeof(struct Node));head=q;while(p){ switch(p->data){case 1:n=p->data1;r=(Lnode*)malloc(sizeof(struct Node));q->next=r;q=q->next;q->data=1;q->data1=n;break;case 2:c=p->data2; if(stackempy2(OPTR))Push2(OPTR,c); else { switch(c){ case '(': Push2(OPTR,c);break;case ')': Popopnd2(OPTR,c2);while(c2!='('){r=(Lnode*)malloc(sizeof(struct Node));q->next=r;q=q->next;q->data=2;q->data2=c2;Popopnd2(OPTR,c2);}break;default: GetTop2(OPTR,c2);while(!compare(c2,c)){ Popopnd2(OPTR,c2);r=(Lnode*)malloc(sizeof(structNode));q->next=r;q=q->next;q->data=2;q->data2=c2;GetTop2(OPTR,c2);}Push2(OPTR,c);break;}}break;default: printf("结点有误");break;}p=p->next;}while(!stackempy2(OPTR)){ Popopnd2(OPTR,c2);r=(Lnode*)malloc(sizeof(struct Node));q->next=r;q=q->next;q->data=2;q->data2=c2;}q->next=NULL;q=head->next;while(q){if(q->data==1) printf("%d ",q->data1);if(q->data==2) printf("%c",q->data2);q=q->next;}houzhuiqiuzhi(head,n);printf("=%d ",n);}void qianzhuiqiuzhi(Lnode2 *p,int &e)//前缀表达式求值{sqstack1 OPND; //运算数栈sqstack2 OPTR; //运算符栈int n;char c;Lnode2 *head;head=p;p=p->next;InitStack1(OPND);InitStack2(OPTR);while(p!=head){switch(p->data){case 1:n=p->data1;Push1(OPND,n);break;case 2:c=p->data2;Push2(OPTR,c);Operatqianzhui(OPND,OPTR);break;default:printf("结点有误 ");break;}p=p->next;}Popopnd1(OPND,n);e=n;}void qianzhui(Lnode *p)//中缀表达式转变为前缀表达式{sqstack2 OPTR; //运算符栈InitStack2(OPTR);int n;char c,c2;Lnode *first;Lnode2 *q,*head,*r,*head2,*s;first=p;p=p->next;q=(Lnode2*)malloc(sizeof(struct Node2));//成立存中缀表达式的双向循环链表head=q;while(p){r=(Lnode2*)malloc(sizeof(struct Node2));q->next=r;r->prior=q;q=q->next;q->data=p->data;q->data1=p->data1;q->data2=p->data2;p=p->next;}q->next=head;head->prior=q;s=(Lnode2*)malloc(sizeof(struct Node2));//成立存前缀表达式的双向循环链表head2=s;while(q!=head){switch(q->data){case 1:n=q->data1;r=(Lnode2*)malloc(sizeof(struct Node2));s->next=r;r->prior=s;s=s->next;s->data=1;s->data1=n;break;case 2:c=q->data2;if(stackempy2(OPTR)) Push2(OPTR,c);else{ GetTop2(OPTR,c2);if(c2==')') Push2(OPTR,c);else{ switch(c){ case ')':Push2(OPTR,c);break;case '(': Popopnd2(OPTR,c2);while(c2!=')'){r=(Lnode2*)malloc(sizeof(struct Node2));s->next=r;r->prior=s;s=s->next;s->data=2;s->data2=c2;Popopnd2(OPTR,c2);}break;default: GetTop2(OPTR,c2);while(!compare(c2,c)){ Popopnd2(OPTR,c2);r=(Lnode2*)malloc(sizeof(struct Node2));s->next=r;r->prior=s;s=s->next;s->data=2;s->data2=c2;GetTop2(OPTR,c2);}Push2(OPTR,c);break;}}}break;default:printf("结点有误 ");break;}q=q->prior;}while(!stackempy2(OPTR)){ Popopnd2(OPTR,c2);r=(Lnode2*)malloc(sizeof(struct Node2));s->next=r;r->prior=s;s=s->next; s->data=2; s->data2=c2;}s->next=head2;head2->prior=s;while(s!=head2){if(s->data==1) printf("%d ",s->data1);if(s->data==2) printf("%c",s->data2);s=s->prior;}qianzhuiqiuzhi(head2,n);printf("=%d ",n);}int main(){ char n[10];char c;int i,j,k,a,b,z,y,e; Lnode *p,*q,*first;i=0;e=1;a=0;b=1;z=0;y=0;p=(Lnode*)malloc(sizeof(struct Node)); first=p;printf("请输入中缀表达式 ");do{ c = getchar();if('0'<=c&&c<='9'){ n[i]=c;i++;}else{ switch (c){ case '+':case '-':case '*':case '/':case '%':case '(':case ')':case '\n':{ if(n[0]>'0'&&n[0]<='9'){ q=(Lnode*)malloc(sizeof(struct Node));p->next=q;p=p->next;for(k=0;k<i;k++){ for(j=0;j<=i-k-2;j++)e=e*10;a=a+(n[k]-'0')*e;e=1;n[k]='0';}p->data=1;p->data1=a;i=0;a=0;}if(c!='\n'){ if(p->data==2){ if(p->data2!=')'&&c!='(')b=0;}q=(Lnode*)malloc(sizeof(struct Node));p->next=q;p=p->next;p->data=2;p->data2=c;if(c=='(') z++;if(c==')') y++;}}default:if(c!='+'&&c!='-'&&c!='*'&&c!='/'&&c!='%'&&c!='\n'&&c!='('&&c!=')')b=0;}}}while (c != '\n');if(z!=y) b=0;p->next=NULL;if(b==0)printf("输入中缀表达式有误 ");else{printf(" 输入 1 中缀表达式求值,输入 2 后缀表达式求值,输入 3 前缀表达式求值 ");scanf("%d",&b);if(b==1) zhongzhui(first); if(b==2) houzhui(first); if(b==3) qianzhui(first); }return 1;}。
中缀转后缀表达式计算报告

目录一、设计思想 (01)二、算法流程图 (02)三、源代码 (04)四、运行结果 (14)五、遇到的问题及解决 (16)六、心得体会 (16)一、设计思想(1)中缀表达式转后缀表达式并计算创建一个数组存储输入的计算表达式。
另创建一个数组储存将要生成的后缀表达式。
创建一个栈储存操作符。
对已存储的表达式数组扫描。
判断当前节点,如果是操作数或’.’,直接加入后缀表达式中,如果是操作符,则比较前一个操作符与当前操作符的优先级。
如果前一个操作符的优先级较高,则将前一个操作符加入后缀表达式中,否则将操作符压入操作符栈。
如果遇到左括号’(’,直接入栈;如果遇到右括号’)’,则在操作符栈中反向搜索,直到遇到匹配的左括号为止,将中间的操作符依次加到后缀表达式中。
当执行完以上操作,发现栈中仍有剩余操作符,则将操作符依次加到后缀表达式中。
此时中缀表达式已经转换成了后缀表达式。
对后缀表达式进行计算。
如果后缀表达式为大于0小于9的字符,则将它转换成浮点型数据并存入数栈中。
如果遇到操作符,则从数栈中提取两个数,进行相应的运算。
依次进行下去,当没有运算符是,运算结束得到最后的结果。
(2)直接表达式求值创建一个数组存储输入的计算表达式。
创建两个栈,一个字符型的栈,一个双精度型的栈。
分别用来存储字符和数。
对已存储的表达式数组扫描。
判断当前节点,如果是操作数和’.’,将字符型的操作数转换为浮点型的数后存入操作数栈。
如果是操作符则判断操作符的优先级。
如果字符栈中已存储符号的优先级小于要存入的字符的优先级,则直接让字符入操作符栈。
如果字符栈中已存储符号的优先级大于或等于要存入的字符的优先级,则取出操作符栈中的一个字符和操作数栈中的两个数进行计算,然后将结果存入操作数栈中,同上进行下去,直到字符栈中已存储符号的优先级小于要存入的字符的优先级时,将操作符存入操作符栈中。
当遇到左括号’(’,将左括号直接存入操作符栈中。
当遇到右括号’)’,则在操作符栈中反向搜索,并且每搜到一个字符就在操作数栈中取两个数进行相应的计算。
C语言实现中缀表达式转换为后缀表达式

C语⾔实现中缀表达式转换为后缀表达式本⽂实例为⼤家分享了C语⾔实现中缀表达式转后缀表达式的具体代码,供⼤家参考,具体内容如下中缀表达式转换为后缀表达式(思路)1.创建栈2.从左向右顺序获取中缀表达式a.数字直接输出b.运算符情况⼀:遇到左括号直接⼊栈,遇到右括号将栈中左括号之后⼊栈的运算符全部弹栈输出,同时左括号出栈但是不输出。
情况⼆:遇到乘号和除号直接⼊栈,直到遇到优先级⽐它更低的运算符,依次弹栈。
情况三:遇到加号和减号,如果此时栈空,则直接⼊栈,否则,将栈中优先级⾼的运算符依次弹栈(注意:加号和减号属于同⼀个优先级,所以也依次弹栈)直到栈空或则遇到左括号为⽌,停⽌弹栈。
(因为左括号要匹配右括号时才弹出)。
情况四:获取完后,将栈中剩余的运算符号依次弹栈输出例:⽐如将:2*(9+6/3-5)+4转化为后缀表达式 2 9 6 3 / +5 - * 4 +转换算法代码如下:/*中缀转后缀函数*/void Change(SqStack *S,Elemtype str[]){int i=0;Elemtype e;InitStack(S);while(str[i]!='\0'){while(isdigit(str[i])){/*过滤数字字符,直接输出,直到下⼀位不是数字字符打印空格跳出循环 */printf("%c",str[i++]);if(!isdigit(str[i])){printf(" ");}}/*加减运算符优先级最低,如果栈顶元素为空则直接⼊栈,否则将栈中存储的运算符全部弹栈,如果遇到左括号则停⽌,将弹出的左括号从新压栈,因为左括号要和⼜括号匹配时弹出,这个后⾯单独讨论。
弹出后将优先级低的运算符压⼊栈中*/ if(str[i]=='+'||str[i]=='-'){if(!StackLength(S)){PushStack(S,str[i]);}else{do{PopStack(S,&e);if(e=='('){PushStack(S,e);}else{printf("%c ",e);}}while( StackLength(S) && e != '(' );PushStack(S,str[i]);}}/*当遇到右括号是,把括号⾥剩余的运算符弹出,直到匹配到左括号为⽌左括号只弹出不打印(右括号也不压栈)*/else if(str[i]==')'){PopStack(S,&e);while(e!='('){printf("%c ",e);PopStack(S,&e);}}/*乘、除、左括号都是优先级⾼的,直接压栈*/else if(str[i]=='*'||str[i]=='/'||str[i]=='('){PushStack(S,str[i]);}else if(str[i]=='\0'){break;}else{printf("\n输⼊格式错误!\n");return ;}i++;}/*最后把栈中剩余的运算符依次弹栈打印*/while(StackLength(S)){PopStack(S,&e);printf("%c ",e);}}完整代码如下:#include<stdio.h>#include<stdlib.h>#include<ctype.h>#include<assert.h>#define INITSIZE 20#define INCREMENT 10#define MAXBUFFER 20#define LEN sizeof(Elemtype)/*栈的动态分配存储结构*/typedef char Elemtype;typedef struct{Elemtype *base;Elemtype *top;int StackSize;}SqStack;/*初始化栈*/void InitStack(SqStack *S){S->base=(Elemtype*)malloc(LEN*INITSIZE);assert(S->base !=NULL);S->top=S->base;S->StackSize=INITSIZE;}/*压栈操作*/void PushStack(SqStack *S,Elemtype c){if(S->top - S->base >= S->StackSize){S->base=(Elemtype*)realloc(S->base,LEN*(S->StackSize+INCREMENT));assert(S->base !=NULL);S->top =S->base+S->StackSize;S->StackSize+=INCREMENT;}*S->top++ = c;}/*求栈长*/int StackLength(SqStack *S){return (S->top - S->base);}/*弹栈操作*/int PopStack(SqStack *S,Elemtype *c){if(!StackLength(S)){return 0;}*c=*--S->top;return 1;}/*中缀转后缀函数*/void Change(SqStack *S,Elemtype str[]){int i=0;Elemtype e;InitStack(S);while(str[i]!='\0'){while(isdigit(str[i])){/*过滤数字字符,直接输出,直到下⼀位不是数字字符打印空格跳出循环 */printf("%c",str[i++]);if(!isdigit(str[i])){printf(" ");}}/*加减运算符优先级最低,如果栈顶元素为空则直接⼊栈,否则将栈中存储的运算符全部弹栈,如果遇到左括号则停⽌,将弹出的左括号从新压栈,因为左括号要和⼜括号匹配时弹出,这个后⾯单独讨论。
中缀表达式转换为后缀表达式C语言程序

//1.h#ifndef STACK_H#define STACK_H#include<stdio.h>#include<stdlib.h>typedef struct astack *Stack;typedef struct astack{int top;int maxtop;char* data;}Astack;Stack NewEmpty(int size){Stack S=(Stack)malloc(sizeof(Astack)); S->maxtop=size;S->top=-1;S->data=(char*)malloc(size*sizeof(char)); return S;}int StackEmpty(Stack S){return S->top<0;}int StackFull(Stack S){return S->top==S->maxtop;}int Peek(Stack S){return S->data[S->top];}void Push(char x,Stack S){if(StackFull(S)){printf("Stack is full!\n");exit(1);}elseS->data[++S->top]=x;int Pop(Stack S){if(StackEmpty(S)){printf("Stack is empty!\n");exit(1);}elsereturn S->data[S->top--];}Stack NewStack(int size){Stack S=NewEmpty(size);int i,x,num;printf("Please enter the number of data:\n"); scanf("%d",&num);for(i=0;i<num;i++){printf("Please enter the %d date:\n",i+1); scanf("%c",&x);Push(x,S);}return S;}void ShowStack(Stack S){int i;for(i=0;i<=S->top;i++){printf(" %c",S->data[i]);}printf("\n");}#endif#include<stdio.h>#include<stdlib.h>#include<ctype.h>#include"1.h"#define MAX 30int Precedence(char ch){if(ch=='+'||ch=='-')return 2; else if(ch=='*'||ch=='/')return 3; else if(ch=='('||ch==')')return 4; else if(ch=='@')return 1;else return 0;}void Change(char *s1,char *s2) {Stack S=NewEmpty(MAX);int i=0,j=0,one=0;char ch=s1[i];Push('@',S);while(ch!='@'){if(ch==' ')ch=s1[++i];else if(isalnum(ch)!=0){if(one==1){s2[j++]=' ';}s2[j++]=ch;ch=s1[++i];one=0;}else if(ch=='('){Push(ch,S);ch=s1[++i];one=1;}else if(ch==')'){while(Peek(S)!='(')s2[j++]=Pop(S);Pop(S);ch=s1[++i];one=1;}else if(ch=='+'||ch=='-'||ch=='*'||ch=='/'){while(Peek(S)!='('&&Precedence(Peek(S))>=Precedence(ch)) {s2[j++]=Pop(S);one=1;}Push(ch,S);ch=s1[++i];one=1;}}while(StackEmpty(S)!=1){s2[j++]=Pop(S);one=1;}s2[j]='\0';}int main(){char s1[MAX],s2[MAX];printf("Enter the equation:\n");gets(s1);Change(s1,s2);printf("%s\n",s2);return 0;}。
栈的应用1——超级计算器(中缀与后缀表达式)C语言
栈的应⽤1——超级计算器(中缀与后缀表达式)C语⾔这⾥要学的程序主要⽤来实现⼀个功能——输⼊表达式输出结果,也就是⼀个计算器。
效果如下:这个程序主要有两个步骤:1、把中缀表达式转换为后缀表达式;2、计算后缀表达式的结果。
⾸先先明⽩⼏个问题:1、为什么要转换为后缀表达式?因为后缀表达式容易实现计算机计算结果。
(可以百度⼀下后缀表达式,⼜称逆波兰式)2、怎么把中缀表达式转换为后缀表达式?3、怎么⽤后缀表达式输出结果?相信如果弄明⽩了上⾯⼏个问题,有C语⾔基础的同学就可以编出这个程序啦。
⽽后⾯两个问题都要⽤到⼀个数据结构——栈。
实际上数据结构只是⼀种思想,⼀种思维,是连接⼈脑与计算机的桥梁(纯属个⼈杜撰= =) 好,那么我们先学怎么把中缀表达式转换为后缀表达式。
为了简化问题,我们不妨设输⼊的数字都是⼀位整数,这样读⼊的时候只需要以字符的⽅式逐个读⼊即可,也就是说读⼊的必定是数字或者+-*/,读到回车视为结束;另外不妨直接将结果打印到屏幕上,也就是说结果不必存储(这样我们可以更多地关注算法本⾝,⽽⾮输⼊输出⽅式的细枝末节) 类似上⾯的图⽚,它的后缀表达式是 9 3 1 - 2 * + 5 2 / + 怎么得到的呢?下⾯开始讲这个转换的算法: 1、设置⼀个栈,栈底填⼀个"@"作为结束符(当然也可以⽤别的符号,⾄于为什么要⽤⼀会讲优先级的时候会说); 2、开始逐个字符读⼊; 3、如果读⼊的是数字,直接打印printf("%c ",c);(数字后⾯打印⼀个空格作为间隔符,要不然没法看了931-。
不解释) 4、如果读⼊的是"("直接进栈; 5、如果读⼊的是")",说明前⾯肯定读⼊过⼀个"("找到这个左括号,把两者之间的符号逐个弹栈(这⾥要说明的是,括号不必打印,因为后缀表达式没有括号); 6、如果不是上⾯的⼏种情况,那必定是+-*/中的⼀个啦,这样来说就容易多了。
(完整版)数学表达式计算(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 栈。
算法笔记--中缀表达式转后缀表达式后缀表达式计算
算法笔记--中缀表达式转后缀表达式后缀表达式计算中缀表达式转后缀表达式规则中缀表达式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. 读到" + ",因为栈顶元素" * "的优先级⽐它⾼,所以弹出" * "并输出,同理,栈中下⼀个元素" + "优先级与读到的操作符" + "⼀样,所以也要弹出并输出。
然后再将读到的" + "压⼊栈中。
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、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
中缀表达式转后缀表达式中缀表达式转后缀表达式的规则。
1.遇到操作数:直接输入到后缀表达式栈2.遇到运算符,直接入操作符栈3.遇到左括号:直接将其入栈4.遇到右括号:执行出栈操作,并将出栈的元素输出,直到弹出栈的是左括号,左括号不输出。
5.遇到其他运算符:加减乘除:弹出所有优先级大于或者等于该运算符的栈顶元素,然后将该运算符入栈6.最终将操作符栈中的元素依次出栈,输出到后缀表达式栈。
以下是自己写的代码。
亲测没有问题。
(模拟一个计算器,可以带括号,中间可以空格,只支持整数输入,但是输出结果精确到小数后6位)#include "stdio.h"#define MAX_LEN 100typedef struct cal{unsigned char isOper;//是否是操作数1,操作符0.操作数double Num; //值。
或者是操作符的ASCII值}STRUCT_CAL;#define IS_NUM 0x00#define IS_OPER 0x01STRUCT_CAL stackCal[MAX_LEN];STRUCT_CAL stackCalBack[MAX_LEN];unsigned char topCal;char stackOper[MAX_LEN];unsigned char topOper;/****************************************************************** 堆栈初始化*****************************************************************/void stackInit(void){int i;for(i=0;i<MAX_LEN;i++){stackCal[i].isOper = 0;stackCal[i].Num = 0;stackOper[i] = 0;}topCal = topOper = 0;}/***************************************************************** * 返回堆栈的栈顶,返回后栈顶减一*****************************************************************/ STRUCT_CAL * stackCalPop(void){if(topCal == 0)return (STRUCT_CAL *)0;return stackCal+(--topCal);}/***************************************************************** * 计算表达式入栈*****************************************************************/void stackCalPush(double num, unsigned char isOper){if(topCal>=MAX_LEN)return;stackCal[topCal].Num = num;stackCal[topCal].isOper= isOper;topCal++;}/***************************************************************** * 操作符出栈*****************************************************************/char stackOperPop(void){if(topOper == 0)return 0;return stackOper[--topOper];}/****************************************************************** 操作符入栈*****************************************************************/void stackOperPush(char oper){if(topOper >=MAX_LEN)return;stackOper[topOper++] = oper;}/****************************************************************** 比较两个sour sour1 的优先级* 1 sour >= sour1 直接入操作符栈* 0 sour < sour1 直接入计算表达式栈*****************************************************************/ unsigned char comparPrior(char sour, char sour1){if(sour =='\0' ||sour1 == '\0') return 1;switch(sour){case '+':case '-':if(sour1 == '*' ||sour1 == '/'||sour1 == '+' ||sour1 == '-' ){return 0;}else{return 1;}break;case '*':case '/':if(sour1 == '*' ||sour1 == '/'||sour1 == '+' ||sour1 == '-'||sour1 == '('){return 1;}else{return 0;}break;default:return 1;break;}}/****************************************************************** 将输入的字符串转换为栈*****************************************************************/void StrToCal(char *pStr){int tmpNum = 0;char tmpOper;char islastNum = 0;//判断上一个字符是什么。
如果是符号,现在碰到‘-’,那么数字就是负数char isNumNegative = 0;while(*pStr != '\0'){switch(*pStr){case '+':while(comparPrior('+',stackOper[topOper-1]) == 0){stackCalPush(stackOperPop(), IS_OPER);if(topOper<1)break;}stackOperPush('+');pStr++;islastNum = 0;break;case '-':if(islastNum == 0) //如果上一个字符是操作符,那么接下来的数字是负数{isNumNegative = 1;// 1代表是负数pStr++;break;}while(comparPrior('-',stackOper[topOper-1]) == 0){stackCalPush(stackOperPop(), IS_OPER);if(topOper<1)break;}stackOperPush('-');pStr++;islastNum = 0;break;case '*':while(comparPrior('*',stackOper[topOper-1]) == 0) {stackCalPush(stackOperPop(), IS_OPER);if(topOper<1)break;}stackOperPush('*');pStr++;islastNum = 0;break;case '/':while(comparPrior('/',stackOper[topOper-1]) == 0) {stackCalPush(stackOperPop(), IS_OPER);if(topOper<1)break;}stackOperPush('/');pStr++;islastNum = 0;break;case '(':stackOperPush('(');pStr++;islastNum = 0;break;case ')':while((tmpOper = stackOperPop()) != '('){stackCalPush(tmpOper, IS_OPER);}pStr++;islastNum = 0;break;case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':while((*pStr >='0' )&& (*pStr <='9')){tmpNum = tmpNum *10 +*(pStr++) - '0';}if(isNumNegative){isNumNegative = 0;tmpNum = -tmpNum;}stackCalPush(tmpNum, IS_NUM);tmpNum = 0;islastNum = 1;break;case ' ':pStr++;break;default:pStr++;break;}}while(topOper) //如果最后操作符栈还有数据,直接入计算栈{stackCalPush(stackOperPop(), IS_OPER);}}/***************************************************************** * 显示转换后的后缀表达式,用于调试,看转换是否正确*****************************************************************/ void dispCalc(void){int i = 0;printf("\n");for(i = 0;i<topCal;i++){if(stackCal[i].isOper == IS_NUM){printf("%d",(int)stackCal[i].Num);}else if(stackCal[i].isOper == IS_OPER){printf("%c",(char)stackCal[i].Num);}}}/***************************************************************** * 计算后缀表达式的计算结果*****************************************************************/void suffixExpression(void){int i = 0;int tmpTop;double num1,num2;for(i = 0;i<topCal;i++){stackCalBack[i] = stackCal[i];}i = 0;tmpTop = topCal;topCal = 0;while(1){if(stackCalBack[i].isOper == IS_OPER){num1 = stackCalPop()->Num;num2 = stackCalPop()->Num;switch((char)stackCalBack[i].Num){case '+':stackCalPush(num2+num1, IS_NUM);break;case '-':stackCalPush(num2-num1, IS_NUM);break;case '*':stackCalPush(num2*num1, IS_NUM);break;case '/':stackCalPush((int)num2/num1, IS_NUM);break;default :break;}}else{stackCalPush(stackCalBack[i].Num, IS_NUM);}i++;if(i>=tmpTop) break;}printf("\nThe result is : %f\n", stackCal[0].Num);stackInit();}int main(void){char input[MAX_LEN];stackInit();while(1){printf("Please input calculate Expression :\n");gets(input);StrToCal(input);//dispCalc();suffixExpression();}return 0;}。