C语言下表达式的自动计算两种方式报告+源代码.docx
《C语言下表达式的自动计算两种方式报告+源代码.docx》由会员分享,可在线阅读,更多相关《C语言下表达式的自动计算两种方式报告+源代码.docx(40页珍藏版)》请在冰豆网上搜索。
![C语言下表达式的自动计算两种方式报告+源代码.docx](https://file1.bdocx.com/fileroot1/2023-2/28/aaad5fde-c5c1-49b6-b327-ad7a3dc47040/aaad5fde-c5c1-49b6-b327-ad7a3dc470401.gif)
C语言下表达式的自动计算两种方式报告+源代码
一、设计思想
第一种算法:
将中缀表达式转为后缀表达式,然后通过后缀表达式计算出算术表达式的结果。
核心思想:
第一步:
中缀变后缀。
首先,我们做出一个统一的Node结构体,结构体内部包含四个属性,分别是操作符的字符‘op’,char类型;操作符的优先级‘level’,int类型;数字的浮点数数值‘od’,float类型;Node的标识符,int类型。
然后,定义一个Node结构体类型的数组*listNode,这里的*listNode用的是全局变量,为了方便在得到后缀表达式后,不需再传递给计算的方法。
定义一个存放操作符的栈,遍历用户输入的算术表达式(不考虑错误情况),在遍历的过程中如果遇到数字,直接将数字存放在*listNode里面;如果遇到了操作符,则判断操作符栈目前是不是为空,如果为空,直接将遇到的操作符放入操作符栈中,如果操作符栈不为空,那么观察操作符栈中栈顶的操作符,然后再次判断当前遇到的操作符的优先级是不是比栈顶的操作符的优先级高,如果是,那么将当前的操作符入操作符栈;如果不是,那么将操作符栈的栈顶操作符取出,追加到*listNode中,然后继续观察栈顶操作符,直到当前的操作符的优先级比栈顶操作符的优先级高或者操作符栈为空时,将当前操作符入操作符栈。
如果遇到了左括号,那么定义其优先级为最低,然后直接将左括号入操作符栈。
如果遇到了右括号,那么开始从操作符栈中取出操作符追加到*listNode中,直到遇到了与之对应的左括号,然后将左括号和右括号一起销毁。
当遍历完成了算术表达式之后,这时判断操作符栈是否为空,如果不为空,那么从操作符栈中依次取出栈顶操作符追加到*listNode中,直到操作符栈为空,那么就代表我们将中缀表达式转变成为了后缀表达式。
第二步:
通过得到的后缀表达式,计算算术表达式。
首先,定义一个数字栈用来存放数值。
然后,遍历*listNode中的每一个Node,如果Node是一个数字,那么就将数字入数字栈,如果Node是一个操作符,那么就从数字栈中依次取出栈顶的两个数字,然后根据操作符计算这两个数字,将得到的结果再次入数字栈,直到遍历*listNode完成,最终数字栈中会只剩下一个Node,那就是我们计算出算术表达式的结果,将结果返回给main函数用来输出。
第二种算法:
一步计算法,在遍历表达式的同时完成算术表达式的计算。
首先,定义两个栈,一个用来存放数字的栈,一个用来存放操作符的栈。
然后,遍历用户输入的算术表达式(不考虑错误的情况),在遍历的过程中,如果遇到数字,那么将该数字存放在数字栈中,如果遇到了操作符,则判断操作符栈目前是不是为空,如果为空,直接将遇到的操作符放入操作符栈中,如果操作符栈不为空,那么观察操作符栈中栈顶的操作符,然后再次判断当前遇到的操作符的优先级是不是比栈顶的操作符的优先级高,如果是,那么将当前的操作符入操作符栈;如果不是,那么将操作符栈的栈顶操作符取出,然后从数字栈中依次取出栈顶的两个数字,然后根据取出的操作符来计算这两个数字,将得到的结果再次入数字栈,直到当前的操作符的优先级大于观察的操作符栈顶操作符的优先级时,将当前的操作符入操作符栈;如果遇到了左括号,那么定义其优先级为最低,然后直接将左括号入操作符栈。
如果遇到了右括号,那么开始从操作符栈中取出操作符,从数字栈中取出两个栈顶数字,然后根据取出的操作符计算两个数字,将得到的结果如数字栈,直到遇到了与之对应的左括号,然后将左括号和右括号一起销毁。
最后,当遍历完成用户输入的算术表达式后,判断目前操作符栈是否为空,如果不为空,那么从操作符栈中取出栈顶操作符,从数字栈中依次取出两个栈顶数字,然后根据取出的栈顶操作符计算两个数字,将得到的结果再次入数字栈,直到当前的操作符栈为空时,那么数字栈中会只剩下一个数字,那就是我们计算出算术表达式的结果,将结果返回给main函数用来输出。
二、算法流程图
1.下面给出整体程序的算法流程图:
图1整体程序的算法流程图
说明:
图1是整体程序的流程图,体现了本程序的整体用户操作和程序提供的功能,也体现了本程序的总体思想。
其中,当表达式计算完成,或是表达式输入错误,程序提供了再次请求用户输入表达式的功能。
2.下面给出得到后缀表达式的算法流程图:
图2得到后缀表达式的算法流程图
说明:
图2是通过用户输入的表达式得到其后缀表达式的算法流程图,整体描述了得到后缀表达式的过程,但是还有一些细节并没有刻画出来。
其中,大方向有两个分支,就是判断进来的字符是否为数字,然后,当得知进来的字符不是数字时,又分成了两个分支,即判断该字符是否为运算操作符或是左括号,因为他们的操作基本类似;第二分支就是进来的字符为右括号。
3.下面给出通过后缀表达式得到计算结果的算法流程图:
图3通过后缀表达式得到结果的算法流程图
说明:
图3是通过后缀表达式得到最终计算结果的算法流程图,其中,当整个后缀表达式遍历完成后,我们的数字栈中只会剩下一个Node元素,这个元素即为最终计算的结果。
4.下面给出一步直接计算表达式的算法流程图:
图4一步直接计算表达式得到结果的算法流程图
说明:
图4是一步直接计算表达式得到结果的算法流程图,其核心思想和得到后缀表达式基本类似,不同之处是,如果遍历过程中遇到了数字,将数字入数字栈,而当遇到操作符后,如果优先级小,那么直接从数字栈依次取出两个栈顶数字,进行计算,将计算的结果再次入数字栈。
三、源代码
下面给出计算表达式的原代码,两种方法写在了一个程序里面,其中有个GetHzbdsByExpr的方法,是得到后缀表达式的方法,有个GetResultByListNode的方法,是通过后缀表达式得到计算结果的方法,然后有个GetResultWithOneStep的方法,是一步直接计算结果的方法,都有注释标识。
源代码:
#include"stdio.h"
#include"conio.h"
#include"string.h"
#include"stdlib.h"
structNode*listNode[100];/*定义一个长度为100的Node类型的数组,用来存放转换完成的后缀表达式*/
typedefstructNode/*定义Node类型的结构体,用来代表数字和操作符*/
{
charop;/*操作符的字符*/
intlevel;/*操作符的优先级*/
floatod;/*数字的值*/
inttype;/*Node的类型标识符*/
}Node;
voidinitNode(Node*nd,charc,intle,floatval,intty)/*初始化Node*/
{
nd->op=c;/*操作符的字符,赋值为传过来的字符*/
nd->level=le;/*操作符的优先级,赋值为传过来的优先级级别*/
nd->od=val;/*赋值为传过来的浮点数数值*/
nd->type=ty;/*赋值标识符*/
}
typedefstructMyStack/*定义一个栈的结构体,用来存放操作符和数字*/
{
Node*listNd[100];/*定义一个长度为100的node类型的数组,用来当做栈*/
inttop;/*栈顶索引*/
}MyStack;
voidinitMyStack(MyStack*ms)/*初始化栈*/
{
ms->top=0;/*初始化的时候栈顶指向0*/
}
intIsEmpty(MyStack*ms)/*判断栈是否为空*/
{
if(ms->top==0)
return0;/*0代表为空*/
return1;
}
voidPush(Node*nd,MyStack*ms)/*向ms栈中追加一个node类型的nd*/
{
ms->listNd[ms->top]=nd;/*追加node*/
ms->top++;/*将栈顶索引指向下一项*/
}
Node*Pop(MyStack*ms)/*从ms栈中取出栈顶的node*/
{
if(ms->top!
=0)/*如果栈不为空*/
{
ms->top--;/*将栈顶索引指向上一项*/
returnms->listNd[ms->top];/*返回栈顶node*/
}
returnNULL;/*如果栈为空,那么返回NULL*/
}
Node*Top(MyStack*ms)/*观察栈顶的node*/
{
inttop=ms->top;/*获得当前的栈顶索引*/
Node*topNode;/*定义一个node*/
if(top!
=0)
{
topNode=ms->listNd[top-1];/*得到栈顶的Node*/
returntopNode;/*返回栈顶Node*/
}
else
returnNULL;
}
char*cutStr(char*expr,intbegin,intend)/*截取字符串的方法,从begin开始,截取到end*/
{
char*result=NULL;/*定义截取到的结果字符数组*/
intresultCount=0;/*要截取的字符串的长度*/
resultCount=end-begin+1;/*截的末尾索引减去起始索引加1即为要截取的长度*/
result=(char*)malloc(sizeof(char)*resultCount+1);/*多申请一个字节,用于存放结束句'\0'*/
if(result==NULL)/*如果没有开辟成功空间*/
{
printf("Errormallocmemoryinfunction.\n");/*打印开辟内存空间错误*/
returnNULL;
}
strncpy(result,expr+begin,resultCount);/*从expr+begin这个地址开始,截取resultCount个字符赋给result*/
result[resultCount]='\0';/*赋值结果字符数组的最后一位为‘\0’*/
returnresult;
}
voidGetHzbdsByExpr(char*expr)/*得到后缀表达式的方法*/
{
intindex=0,indexnow,tempindex=0,i=0,listIndex=0;/*index-主索引;indexnow-在截取字符串时代表当前索引值;tempindex-副索引;i-控制循环;listIndex-后缀表达式的项编号*/
floattempn;/*即时用的数字*/
charstr[100]={""};/*截取字符串时用到的临时存放字符的数字*/
char*c={""};/*主索引遍历时遍历到位置的字符*/
char*tempc={""};/*即时用的字符*/
structMyStack*opStack=(MyStack*)malloc(sizeof(MyStack));/*定义一个操作符栈,并为之开辟空间*/
structNode*node=(Node*)malloc(sizeof(Node));/*定义一个Node元素*/
initMyStack(opStack);/*初始化操作符栈*/
listNode[0]=NULL;/*清空存放后缀表达式的数组*/
while(index{
structNode*tempNode=(Node*)malloc(sizeof(Node));/*每次循环里面重新定义这些node*/
structNode*topNode=(Node*)malloc(sizeof(Node));
structNode*popNode=(Node*)malloc(sizeof(Node));
c=cutStr(expr,index,index);/*得到当前索引位置的字符*/
if(*c>='0'&&*c<='9')
{
str[0]=*c;/*把这个字符加到str数组中*/
tempindex=0;/*要截取的字符的长度*/
indexnow=index+1;/*从主索引下一个开始继续遍历*/
tempc=cutStr(expr,indexnow,indexnow);/*主索引的下一个字符*/
while(indexnow='0')&&(*tempc<='9')||(*tempc=='.')))
{
tempindex=tempindex+1;/*满足条件,要截取的字符长度加1*/
indexnow=indexnow+1;/*指向下一个字符*/
str[tempindex]=*tempc;/*将这个字符追加到一个数组中*/
tempc=cutStr(expr,indexnow,indexnow);/*下一个字符*/
}
str[tempindex+1]='\0';/*遍历完一个数值之后,数组中数值的下一位赋值为‘0’*/
tempn=atof(&str[0]);/*将数组中的数值转成float类型的数字*/
initNode(tempNode,'?
',-100,tempn,1);/*type=1代表node的类型为数字*/
listNode[listIndex]=tempNode;/*将这个tempNode添加到后缀表达式的listNode中*/
listIndex++;/*后缀表达式的数组长度加1,指向下一个空位*/
index=index+tempindex+1;/*整个截取数值的工作结束,将主索引向后移动tempindex+1个位置*/
}
if(*c=='+'||*c=='-')
{
initNode(tempNode,*c,1,-100,2);/*1代表'+'和'-'的优先级,type=2代表node的类型为操作符,-100为随意赋值给od*/
if(IsEmpty(opStack)==0)
{
Push(tempNode,opStack);/*如果字符栈为空,直接入栈*/
index++;/*主索引自加*/
}
else
{
topNode=Top(opStack);/*如果字符栈不为空,得到栈顶字符*/
while(IsEmpty(opStack)==1&&tempNode->level<=topNode->level)
{
popNode=Pop(opStack);/*如果目前的操作符的优先级小于栈顶操作符的优先级,就将栈顶操作符取出*/
listNode[listIndex]=popNode;/*将取出的操作符node放入后缀表达式的数组中*/
topNode=Top(opStack);/*继续观察栈顶操作符*/
listIndex++;/*后缀表达式数字加一位*/
}
Push(tempNode,opStack);/*当目前的操作符的优先级大于栈顶操作符的优先级时,将目前的操作符入操作符栈*/
index++;
}
}
if(*c=='*'||*c=='/'||*c=='%')
{
initNode(tempNode,*c,2,-100,2);/*2代表'*'、'/'和'%'的优先级,比'+'和'-'的优先级高*/
if(IsEmpty(opStack)==0)
{
Push(tempNode,opStack);/*如果字符栈为空,直接入栈*/
index++;/*主索引自加*/
}
else
{
topNode=Top(opStack);/*如果字符栈不为空,得到栈顶字符*/
while(IsEmpty(opStack)==1&&tempNode->level<=topNode->level)
{
popNode=Pop(opStack);/*如果目前的操作符的优先级小于栈顶操作符的优先级,就将栈顶操作符取出*/
listNode[listIndex]=popNode;/*将取出的操作符node放入后缀表达式的数组中*/
topNode=Top(opStack);/*继续观察栈顶操作符*/
listIndex++;/*后缀表达式数字加一位*/
}
Push(tempNode,opStack);/*当目前的操作符的优先级大于栈顶操作符的优先级时,将目前的操作符入操作符栈*/
index++;
}
}
if(*c=='(')
{
initNode(tempNode,*c,-1,-100,2);/*左小括号的优先级为-1*/
Push(tempNode,opStack);/*左小括号直接入栈*/
index++;
}
if(*c==')')
{
topNode=Top(opStack);/*得到栈顶*/
while(IsEmpty(opStack)==1&&(topNode->op!
='('))/*观察栈顶,如果栈顶不是左括号*/
{
popNode=Pop(opStack);/*取出栈顶*/
listNode[listIndex]=popNode;/*加到后缀表达式中*/
listIndex++;
topNode=Top(opStack);/*继续观察栈顶*/
}
Pop(opStack);/*当工作完成后,栈顶一定是一个左括号,直接扔掉*/
index++;
}
if(*c=='[')
{
initNode(tempNode,*c,-2,-100,2);/*左中括号的优先级为-2*/
Push(tempNode,opStack);/*左中括号直接入栈*/
index++;
}
if(*c==']')
{
topNode=Top(opStack);/*得到栈顶*/
while(IsEmpty(opStack)==1&&(topNode->op!
='['))/*观察栈顶,如果栈顶不是左括号*/
{
popNode=Pop(opStack);/*取出栈顶*/
listNode[listIndex]=popNode;/*加到后缀表达式中*/
listIndex++;
topNode=Top(opStack);/*继续观察栈顶*/
}
Pop(opStack);/*当工作完成后,栈顶一定是一个左括号,直接扔掉*/
index++;
}
if(*c=='{')
{
initNode(tempNode,*c,-3,-100,2);/*左花括号的优先级为-3*/
Push(tempNode,opStack);/*左花括号直接入栈*/
index++;
}
if(*c=='}')
{
topNode=Top(opStack);/*得到栈顶*/
while(IsEmpty(opStack)==1&&(topNode->op!
='{'))/*观察栈顶,如果栈顶不是左括号*/
{
popNode=Pop(opStack);/*取出栈顶*/
listNode[listIndex]=popNode;/*加到后缀表达式中*/
listIndex++;
topNode=Top(opStack);/*继续观察栈顶*/
}
Pop(opStack);/*当工作完成后,栈顶一定是一个左括号,直接扔掉*/
index++;
}
}
while(IsEmpty(opStack)==1)/*当遍历的工作做完之后,如果操作符栈不为空*/
{
structNode*popNode=(Node*)malloc(sizeof(Node));
popNode=Pop(opStack);/*取出栈顶*/
listNode[listIndex]=popNode;/*加到后缀表达式中*/
listIndex++;
}
listNode[listIndex]=NULL;/*当得到后缀表达式之后,将最后一个node的下一位赋空。
*/
printf("Postfixexpressionis:
\n");/*输出:
“后缀表达式为:
”*/
for(i=0;i{
node=listNode[i];/*遍历后缀表达式中的每一个node*/
if(node->type==1)/*如果node的type=1,即node是数值,则输出node的数值*/
{
printf("%.2f|",node->od);
}
if(node->type==2)/*如果node的type=2,即node是操作符,则输出node的字符*/
{
printf("%c|",node->op);
}
}
}
floatGetResultByListNode()/*通过后缀表达式得到结果的方法*/
{
floatresult=0;/*定义最终计算的结果,用于方法返回*/
inti=0;/*控制循环*/
floatoda=0,odb=0,odResult=0;/*oda,odb-栈顶的两个数字,odResult-两个数字的计算结果*/
structNode*node=(Node*)malloc(sizeof(Node));/*定义一个Node元素并开辟内存空间*/
structMyStack*odStack=(MyStack*)malloc(sizeof(MyStack));/*定义数字栈并开辟空间*/
initMyStack(odStack);/*初始化数字栈*/
for(i=0;listNode[i]!
=NULL;i++)/*遍历后缀表达式中每一个node*/
{
node=listNode[i];/*得到第i个node*/
if(node->type==1)
{
Push(node,odStack);/*如果node的类型是数值,那么入数栈*/
}
if(node->type==2)
{
structNode*odNode=(Node*)malloc(sizeof(Node));
charc=node->op;
switch(c)/*判断操作符*/
{
case'+':
oda=Pop(odStack)->od;/*从栈顶取出一个数值作为加数*/
odb=Pop(odStack)->od;/*再从栈顶取出一个数值为被加数*/
odResult=odb+oda;/*计算两个数字*/
initNode(odNode,'?
',-100,odResult,1);
Push(odNode,odStack);/*将计算结果再次入数栈*/
break;
case'-':
oda=Pop(odStack)->od;/*从栈顶取出一个数值作为减数*/
odb=Pop(odStack)->od;/*再从栈顶取