表达式运算算法的实现
专 业:班 级:指导教师:姓 名:学 号:
目 录
一、设计思想……………………………………………………….01 二、算法流程图…………………………………………………….01
三、源代码………………………………………………………….04 四、运行结果……………………………………………………….12 五、遇到的问题及解决…………………………………………….13 六、心得体会……………………………………………………….14
一、设计思想
(1)先将中缀表达式转化为后缀表达式,再通过计算后缀表达式求表达式的值。第一遍扫描中缀表达式,需要一个运算符栈和一个数组。运算符栈用来存放运算符,数组用来存放转换成的后缀表达式。首先将中缀表达式挨个扫描。如果是数字,则直接放在后缀表达式数组中,依次存放。如果扫描到的是运算符,则按照以下规则存放:栈空时,任何运算符可直接入栈。栈不空是,如果栈中运算符的优先级高于或等于将要放入栈中的运算符的优先级,则将栈中运算符出栈,放入后缀表达式数组中,直到栈中运算符优先级低于将要放入栈中的运算符的优先级,此时将此运算符放入运算符栈中。如果遇到左括号,则直接将左括号入栈,左括号入栈后优先级最低,其他运算符可直接放入。如果遇到右括号,则将运算符栈中的运算符依次取出放到后缀表达式数组中,直到遇到左括号为止,此时将左括号从栈顶删除。按此方法,直到后缀表达式转换成功。第二遍扫描后缀表达式,此时需要一个数栈。扫描时如果遇到数字,则直接放到数栈中。如果遇到运算符,则将数栈中两个数取出,先取出的放在运算符后面,后取出的放在运算符前面,进行运算符运算。将运算的结果放入栈中。之后接着扫描后缀表达式。另外因为运算数的位数不一定而且还有小数点,所以在扫到一个数时要判断这个数的位数,将这个完整的运算数字符串整个取出,这需要用到一个辅助索引。当栈中只有一个数字时,这个数字就是我们要求的表达式的值。
(2)直接计算表达式的值。这种方法需要两个栈,一个运算符栈,一个数栈。只需扫描一遍中缀表达式,边运算边入栈。当扫描到的为数字是,将其放入数栈中,然后扫描下一个字符。如果扫描到的是运算符,栈空时,任何运算符可直接入栈。栈不空是,如果栈中运算符的优先级高于或等于将要放入栈中的运算符的优先级,则将栈中运算符出栈,并从数栈中取出两个数,先取出的放在后面,后取出的放在前面,进行运算符运算,得出结果后,将其放入数栈中。如果栈顶运算符优先级依然高于或等于将要入栈的运算符优先级,仍然进行以上操作,直到栈顶运算符低于将要放入栈中的的运算符的优先级,此时将该运算符入栈。如果扫描到的是左括号,则直接将其入栈。如果扫描到的是右括号,则将栈顶运算符取出,进行以上运算,直到栈顶为左括号,此时将栈顶左括号删除即可,然后将运算结果放入数栈中。当中缀表达式扫描完,并且运算符栈中全部出栈,数栈中只剩一个数字时,即为运算结果。另外因为运算数的位数不一定而且还有小数点,所以在扫到一个数时要判断这个数的位数,将这个完整的运算数字符串整个取出,这需要用到一个辅助索引。
二、算法流程图
图1是从中缀表达式转为后缀表达式并对后缀表达式进行计算的算法流程图,图中所有图形都是长方形,按箭头顺序依次执行。其中如果箭头向下方向有分叉,则箭头左侧长方形代表“是”,右侧代表“否”。
图2是中缀表达式直接计算的算法流程图。按箭头方向执行。图中如果遇到选择类型的语句,则在箭头有分叉的下一行语句中先声明了选项,然后与后面语句逗号隔开。
具体流程图如下:
图1 中缀转后缀再计算算法流程图
图2 中缀表达式直接计算算法流程图
三、源代码
下面给出的是用中缀表达式转换为后缀表达式再进行计算的算法实现的程序的源代码:
#include//导入要用的包 #include #include #define len 1000 struct opnode {
char data[len]; int top;
}op;//定义字符栈 struct odnode {
int top; float data[len]; }od;//定义数栈
void trans(char str[],char exp[],struct opnode op)//中缀变后缀的方法 {
char ch;
int i=0,t=0;
op.top=-1;//初始字符栈顶为空
ch=str[i];i++; //定义存放字符串的数组 while(ch!='\0')//数组中字符串不为空 {
switch(ch)
{
case'+': //判断是否是'+'、'-'
case'-':
while(op.top!=-1&&op.data[op.top]!='(')//栈不为空且栈顶符号不为'('
{
exp[t++]=op.data[op.top--];//存放后缀表达式的数组添加元素 } op.top++;
op.data[op.top]=ch;//入栈 break;
od.top=-1; //初始数栈顶为空
case'*': //判断是否是'*'、'/'、'%'
case'/': case'%':
while(op.data[op.top]=='*'||op.data[op.top]=='/'||op.data[op.top]=='%')
{
exp[t++]=op.data[op.top--];
}
float count(char exp[])//后缀计算的方法 {
float d=0; char ch,tran[len]; int t=0,i=0; while(ch!='\0') {
switch(ch)
{
case'+':
od.data[od.top-1]=od.data[od.top-1]+od.data[od.top];od.top--;//数栈中取值相加 break;
}
while(op.top!=-1)//栈顶不为空 {
exp[t++]=op.data[op.top];
op.top--;
}//将栈顶元素赋给后缀表达式直到栈为空 exp[t]='\0';
}
ch=str[i];i++;
}//栈顶元素为'*'或'/',存放后缀表达式的数组添加元素 op.data[op.top]=ch;//入栈 break;
op.top++;
case'(': op.top++;op.data[op.top]=ch;break;//扫描若是'(',入栈
case')': while(op.data[op.top]!='(')//不是左括号出栈 {
exp[t++]=op.data[op.top--]; }//栈顶元素不为'(',出栈 op.top--;//'('出栈 break;
case'=':break;
default: while(ch>='0'&&ch
exp[t++]=ch;
ch=str[i++];
}//扫描是否是数字或小数点,存入数组 i--;
exp[t]='|';t++;//分隔后缀中的数值元素 break;
ch=exp[t];t++;
case'-': } main() {
}
return od.data[od.top];//返回计算结果
}
ch=exp[t];t++;
od.top++; od.data[od.top]=d;
od.data[od.top-1]=od.data[od.top-1]-od.data[od.top];od.top--;//数栈中取值相减 break;
od.data[od.top-1]=od.data[od.top-1]*od.data[od.top];od.top--;//数栈中取值相乘 break;
{ }
{ } { } break;
case'*':
case'/': if(od.data[od.top]!=0)
od.data[od.top-1]=od.data[od.top-1]/od.data[od.top];od.top--;//数栈中取值相除 else
printf("\n 0不能做被除数\n");//若除数为0则输出此语句
case'%':if(od.data[od.top-1]!=0)
od.data[od.top-1]=fmod(od.data[od.top-1],od.data[od.top]); od.top--;//数栈中取值取余 else
{printf("0不能被任何值取余");}//若除数为0输出此语句
break;
{
tran[i]=ch;//把元素存入字符串 }
tran[i]='\0';//结束表示数字的字符串 i=0;
d=atof(tran);//字符串转化成数
i++; ch=exp[t]; t++;
default: while(ch>='0'&&ch
char str[len],exp[len]; }
struct opnode op;
printf("输入一个计算表达式:\n"); gets(str); trans(str,exp,op);
printf("表达式结果: %f\n",count(exp)); scanf("%d\n"); return 0;
printf("后缀表达式:%s\n",exp);
下面给出的是用中缀表达式直接进行计算的算法实现的程序的源代码:
#include #include #include #define MAX 100 struct opnode { };
struct odnode { };
void push_op(struct opnode *op,char c) /*定义op 栈的进栈函数*/ { }
void pop_op(struct opnode *op) {
if(op->top_op
/*否则,进行出栈操作*/
/*如果栈为空,不进行操作*/ /*定义op 栈的出栈函数*/
if(op->top_op>=MAX-1) { } else { }
op->top_op++; op->str[op->top_op]=c;
/*否则,进行进栈操作*/
/*如果栈满,不进行操作*/
double num[MAX]; int top_od;
/*声明od 栈*/
char str[MAX]; int top_op;
/*包含库函数*/ /*定义栈的最大长度*/ /*声明op 栈*/
else
}
}
op->top_op--;
char top_op(struct opnode *op)
{ return(op->str[op->top_op]);
}
/***************/
void push_od(struct odnode *od,double d) { if(od->top_od>=MAX-1)
{ } else
{ od->top_od++;
od->num[od->top_od]=d; }
}
void pop_od(struct odnode *od)
{ if(od->top_od
{ }
else
{ od->top_od--;
}
}
double top_od(struct odnode *od)
{ return(od->num[od->top_od]);
}
/*判断是否为运算符*/ int is_op(char op)
{ switch(op)
{ case '(':return 1;break; case ')':return 1;break;
case '+':return 1;break;
/*定义op 栈的看栈顶的函数*/
/*定义od 栈的进栈函数*/
/*如果栈为满,不进行操作*/ /*否则,进行进栈操作*/
/*定义od 栈的出栈函数*/
/*如果栈为空,不进行操作*/ /*否则,进行出栈操作*/
/*定义od 栈看栈顶的函数*/
/*op为运算符*/
/*用switch 语句判断*/
case '-':return 1;break; case '*':return 1;break; case '/':return 1;break; case '%':return 1;break; default:return 0;break;
}
}
/*判断运算符优先级*/ int level(char op)
{ switch(op)
{ case '#':return 0;break; case ')':return 0;break; case '(':return 1;break;
case '+':return 2;break; case '-':return 2;break;
case '*':return 3;break; case '/':return 3;break; case '%':return 3;break;
default:return 0;break; }
} /*计算*/
double re(double a,double b,char op)
{ switch(op)
{ case '+':return a+b;
break;
case '-':return a-b; break; case '*':return a*b;
break;
case '/':if(b==0.0)return 0;
else return a/b; break;
case '%':return (int)a%(int)b; break;
default:return 0;break;
}
} /*主函数*/
/*如果是运算符,返回1*/ /*否则,返回0*/
/*op为运算符*/
/*用switch 语句判断,返回值为运算符的栈内优先级*/
/*'#'作为栈底元素*/ /*如果是'#'或')' ,返回0*/ /*如果是' (' ,返回0*/
/*如果是'+'或'-' ,返回2*/ /*如果是'*','/'或'%',返回3*/ /*计算两个浮点数的运算结果*/
/*用switch 语句判断,op 为运算符*/ /*返回a 和b 的和*/
/*返回a 和b 的差*/ /*返回a 和b 的积*/ /*返回a 和b 的商*/
/*如果b=0,返回0,计算结果出错,但程序不会强行终止*/
/*返回a 取余b 的结果*/ /*否则,返回0*/
void main() {
int i,inpos;
/*inpos是inorder[100]的扫描索引*/ /*用于存储表达式*/ /*atof()函数所用的指针*/
char inorder[MAX]; char c,*p=NULL; double a,b,result; char temp_op;
struct opnode oplist; struct odnode odlist; struct opnode *op; struct odnode *od; op=&oplist; od=&odlist; od->top_od=-1; op->top_op=-1; c='#';
push_op(op,c); gets(inorder); /*扫描表达式*/ i=0;
/*i作为扫描inorder[100]的辅助索引*/ /*初始化扫描索引*/
/*用while 循环扫描数组inorder[100]*/
inpos=0; while(c!='\0') {
c=inorder[inpos]; i=inpos;
if(c>='0'&&c
else if(is_op(c)) {
if(level(c)>level(top_op(op))||c=='(') {
/*如果操作符优先级大,压入op 栈中*/
/*如果是操作符*/
p=&inorder[i]; a=atof(p);
push_od(od,a); { } i--; inpos=i;
/*将主索引和辅助索引置为此数字字符的最后
i++;
/*p指针指向此数字字符在数组中的位置*/ /*用atof()函数将数字字符转换为浮点型*/ /*将数字压入od 栈中*/
/*如果是数字字符*/
/*向op 栈栈底放入'#',用于进栈时判断优先级*/ /*接收表达式*/
printf("输入一个中缀表达式(直接计算):\n");/*提示信息*/
/*初始化od 栈*/ /*初始化op 栈*/
/*定义op 栈*/ /*定义od 栈*/ /*定义op 栈的指针*/ /*定义od 栈的指针*/
c=inorder[inpos];
while(inorder[i]>='0'&&inorder[i]
一个位置*/
}
inpos++;
/*主索引自加1,开始下一次扫描*/
}
else if(c==')') { }
else if(level(c)
do { }
while(level(c)
/*操作符压入op 栈*/
temp_op=top_op(op); pop_op(op);
b=top_od(od); pop_od(od);
a=top_od(od); pop_od(od);
/*从od 栈中依次取出两个数字*/ /*计算两个数字的运算结果*/ /*将结果压入od 栈中*/
result=re(a,b,temp_op); push_od(od,result);
/*从op 栈中取出一个操作符*/
/*如果操作符优先级低*/
temp_op=top_op(op); while(temp_op!='(') { }
pop_op(op);
/*将'('出栈*/
temp_op=top_op(op); pop_op(op);
b=top_od(od); pop_od(od);
a=top_od(od); pop_od(od);
result=re(a,b,temp_op);
push_od(od,result);
temp_op=top_op(op);
/*将结果压入od 栈中*/ /*计算两个数字的运算结果*/
/*从od 栈中依次取出两个数字*/
/*从op 栈中取出一个操作符*/
/*从op 栈中出栈,直到栈顶为'('*/
/*如果操作符是')'*/
} {
temp_op=top_op(op); pop_op(op);
b=top_od(od); pop_od(od); a=top_od(od); pop_od(od);
/*从od 栈中依次取出两个数字*/ /*计算两个数字的运算结果*/ /*将结果压入od 栈中*/ /*从od 栈中取出计算结果*/ /*提示信息*/ /*输出中缀表达式*/ /*输出结果*/ /*提示信息*/
}
result=re(a,b,temp_op); push_od(od,result);
/*从op 栈中取出一个操作符*/
/* while循环结束后,表达式已扫描完毕*/
/*如果op 栈中还有操作符*/
while(op->top_op>0)
}/*此while 循环结束后,计算表达式结束,结果存放在od 栈的栈顶*/ result=top_od(od); puts(inorder);
printf("中缀表达式:"); printf("结果=%f",result);
printf("\n按任意键退出!");
四、运行结果
图4 中缀转后缀算法运行结果图
图5 中缀表达式直接计算算法运行结果图
五、遇到的问题及解决
这部分我主要遇到了如下两个问题,其内容与解决方法如下所列: ● 当我基本将我的思路转为程序并编译通过后,我随意的输入几个算式,有些式子得
出的结果正确,而有的却出现错误。如式子为:9.0*(7+8)的结果正确,而当式子为9*12-5或者7/2-3时就会出错。
解决方法:为了发现问题的出处,我又连续试了好几个式子,并亲自计算结果,有些式子的结果很奇怪。其中一些式子本来应该是正值的结果却出现了负值。后来我发现如果式子很短,并且只有加号和乘号就不会出错,于是我就用两个简单的式子验证每个运算符,在验证减号时:7-3得出了-4的答案。于是猜想可能是运算顺序搞反了。接着我又试了试7/3和7%3,得出的结果是0和3。这就验证了我的猜想,于是我就开始检查我的代码,因为在程序中我运用自己建的一个运算函数来进行运算。我就将运算函数中两个数的位置前后对调。结果发现,式子的运算结果正常了,得到了需要的答案。可是还是没弄明白原因,于是我就看了看pop 出这些数的数栈,突然想起栈是有调换数的顺序的功能的,先进栈的数后出来,而我却把先pop 出来的数赋在运算符前,后pop 出来的数放在运算符后面,所以出现了上面的错误,就这样纠正了错误。
● 将字符表示的数字转化成浮点数
解决方法:我的c 语言基础比较薄弱,所学知 识 也不全面。刚开始的思路是先将出现数字的子串计数,得到一共有多少个数字,然后再从子串开始处扫描,依次乘以它的位权,在百位就乘以10的2次方,依次类推。经过很长时间的思考,终于写出了此解决方法,可是却忽略了小数点的存在。又开始用此方法试图解决存在小数点的问题,想了好久也没有解决方法。无奈之下求助于网络,
看有没有什么更好
的解决办法,一经查询知道了stdlib.h 库中有atof 的函数可以将字符串类型的数字转换为浮点型。于是我用一个while 循环将数值子串截取下来存到一个临时数组中,将其成功的转换成浮点数,小数点的情况也解决了。
六、心得体会
大一就开始学c 语言,可是当时学的时候觉得自己好像懂了,但是一编程就会头大。而且当时学的时候也没有好好学,指针、结构体、数组之类的只学了个一知半解,没有完全掌握。这次作业,让我又重新拿起了c 语言课本,把自己以前没有学会的一点点拾起来。复习了以前的c 语言基础知识,一点一点摸索。我知道,我现在的水平特别差,要想学好数据结构,就要打好以前的基础。以后就要多动手操作。书上的例题和算法最好都要自己动手来编程实现。那样可以加深对算法的理解,也可以提高我们的编程水平。同时,很多的东西理解了,可是在实现的时候还是会有很多意想不到的错误发生。在以后的练习和实践中,应该多动手,遇到问题多思考,即使方案不是最优也要想办法自己解决。然后和好的方案进行比较,找出自己的差距在哪。
由于编程基础没有打好,这次的作业寻求了很多网络资源和同学的帮助,在匆匆忙忙中才勉强完成。也深刻地认识到了自己和别人的差距,感觉自己有很大的不足。以前的态度就是不对的,以后一定更加努力地学习,补充以前落下的只是,争取能赶上其他人。
相关文章
- 中缀表达式求值实验报告
- 计算机的基本概念
- 加减乘除四则运算
- 数据结构A教学大纲
- 信息技术算法
- 小数加减法重难点突破
- 圆弧插补的新算法
- 1.1算法的含义
- matlab实现线性卷积和循环卷积
中缀表达式求值实验报告 一.需求分析(要实现的功能描述) 1.问题描述: 在计算机中,算术表达式由常量.变量.运算符和括号组成.由于不同的运算符具有不同的优先级,又要考虑括号,因此,算术表达式的求值不可能严格地从左到右进行.因而在程序设计时 ...
计算机的基本概念 什么是计算机? 计算机是一种能够按照事先存储的程序,自动.高速地对数据进行输入.处理.输出和存储的系统. 计算机能够完成的基本操作及其主要功能: 输入:接受由输入设备(如键盘.鼠标器.扫描仪等)提供的数据. 处理:对数值. ...
微机原理及接口技术 课程设计 题目 学院 专业 班级 姓名 指导教师 加减乘除四则运算程序 自动化学院 电气工程及其自动化 电气1204 李铭昕 李道远 2014 年 12 月 30 日 课程设计任务书 学生姓名: 李铭昕 专业班级: 电气 ...
数据结构A 教学大纲 (Data Structures A) 课程编号: 06311360 学 分: 5.0 学 时: 75 (其中:讲课学时:60 实验学时:0 上机学时:15) 先修课程:离散数学.程序设计基础.面向对象程序设计 适用专 ...
算法与程序设计复习 1.计算机解决问题的过程 P6 2.算法的描述的几种方法P9 用自然语言描述算法 P10 用流程图描述算法P11 流程图图例 用伪代码描述算法 P13 3.认识程序设计语言P14 机器语言--汇编语言--高级语言 4.可 ...
北京市东城区府学胡同小学 王 虹 小数四则运算能力是小学生应该掌握和形成的基础知识和基本能力.通过前面的学习,学生已经掌握了计算简单的一位小数的加减法的方法,如小数点对齐,相同数位也就对齐了:计算时相同数位上的数相加减,从最低位算起,&qu ...
机械设计 JOURNALOFMACHINEDESIGN 16l 圆弧插补的新算法 陆宁 (上海工程技术大学机械工程学院,上海200336) 摘要:在传统插补基本原理的基础上,提出7一种新的偏差判别算法.可大大简化煽程.雀去了象限判别语句.实 ...
(第1课时) §1.1 算法的含义 教学目标:1.通过实例体会算法思想,了解算法的含义与主要特点: 2.能按步骤用自然语言写出简单问题的算法过程学: 3.培养学生逻辑思维能力与表达能力. 教学重点:将问题的解决过程用自然语言表示为算法过程. ...
编号: 数字信号处理 实训 (论文) 说明书 题 目: 用matlab 实现两信号的卷积 院 (系): 应用科技学院 专 业: 电子信息工程 学生姓名: 蒋耀华 学 号: 0801130215 指导教师: 严素清 童有为 纪元法 2011 ...