算术表达式的求解

算术表达式的求解
算术表达式的求解

软件综合课程设计

算术表达式的求解

&车厢调度

二〇一四年六月

目录

算数表达式的求解 (3)

一、前言 (3)

二、问题陈述 (3)

三、需求分析 (3)

四、概要设计 (4)

五、详细设计和编码 (6)

六、上级调试过程 (10)

七、总结与心得 (12)

八、参考文献 (13)

附录(源程序): (13)

车厢调度 (20)

一、问题陈述 (20)

二、问题分析与设计 (20)

三、运行结果 (20)

四、设计体会与总结 (21)

附录(源程序) (21)

算数表达式的求解

一、前言

表达式计算是实现程序设计语言的基本问题之一,也是栈的应用的一个典型例子。设计一个程序,演示用算符优先法对算术表达式求值的过程。

在计算机中,算术表达式由常量、变量、运算符和括号组成。由于不同的运算符具有不同的优先级,又要考虑括号,因此,算术表达式的求值不可能严格地从左到右进行。因而在程序设计时,借助栈实现。

算法输入:一个算术表达式,由常量、变量、运算符和括号组成(以字符串形式输入)。为简化,规定操作数只能为正整数,操作符为+、-*、/,用#表示结束。

算法输出:表达式运算结果。

算法要点:设置运算符栈和操作数栈辅助分析算符优先关系。在读入表达式的字符序列的同时,完成运算符和运算数的识别处理,以及相应运算。

二、问题陈述

(算数表达式的求解)给定一个算数表达式,通过程序求出最后的结果。

要求如下:

1、从键盘输入要求解的算术表达式;

2、采用栈结构进行算数表达式的求解过程;

3、能够判断算数表达式的正确与否;

4、对于错误表达式给出提示;

5、对于正确表达时给出最后的结果。

三、需求分析

有题目可知,程序要求给定一算数表达式并计算最后的结果,我们知道,在

高级语言中,任何一个表达式都是有操作数、运算符和界限符组成。在计算过程中,还要考虑表达式中有无括号以及左右括号之分。由于运算符有优先级的高低,因此一个算数表达是不可能总是按顺序执行。

通过以上可知,可以用栈来实现运算符的优先级完成算术表达式的求解。

为实现算法的优先级,设置两个栈:一个称为操作数栈opnd,用以寄存操作数

和运算结果,另一个为操作符栈optr,用以寄存运算符。

该算法的基本思想是:

(1)首先置操作数栈opnd为空栈,表达式结束符“#”为操作符栈optr的栈底

元素。

(2)依次读入表达式中每个字符,若为操作数,则进opnd栈;若是运算符,则

与optr栈的栈顶运算符比较优先级后做相应操作:若当前操作符大于optr栈的

栈顶,则当前操作符入栈;否则,opnd栈的栈顶元素、次栈顶元素出栈,同时optr栈的栈顶元素也出栈,形成运算,并将结果压入opnd栈,直至整个表达式

求值完毕(即optr栈的栈顶元素和当前读入的字符均为“#”)。

对于算术表达式的输入,本程序采用gets()的方法读入,将运算符‘+’,‘-’,‘*’,‘/’,‘(’,‘)’,‘#’存储在数组中时,定义表达式求解函数,在函数中

判断读入的字符,如果是运算符,将这些字符入操作符optr 栈,并比较优先级,判断是否运算。若读入的字符为‘0’到‘9’之间的数字时,用字符相减转化为整型,然后将转化后的整型再转化为ASCII 的形式压入操作数栈opnd 中。

四、概要设计

1、存储结构设计

本程序主要采用顺序栈结构类型(Stack )来存储表达式计算中的数据。程序中需要建立两个栈,一个栈用于寄存运算符,另一个则用于寄存操作数和计算结果,故需要建立两个顺序栈结构类型。

何一个表达式都是由操作符,运算符和界限符组成的。我们分别用顺序栈来寄存表达式的操作数和运算符。栈是限定于紧仅在表尾进行插入或删除操作的线性表。顺序栈的存储结构是利用一组连续的存储单元依次存放自栈底到栈顶的数据元素,同时附设指针top 指示栈顶元素在顺序栈中的位置,base 为栈底指针,在顺序栈中,它始终指向栈底,即top=base 可作为栈空的标记,每当插入新的栈顶元素时,指针top 增1,删除栈顶元素时,指针top 减1。

2、算数优先级设计 对一任意的表达式,由于表达式中运算符的优先级不同,可能会使表达式不按顺序进行计算。在本程序中定义函数Proceed ()来比较运算符的优先级,而函数中各优先级的比较主要根据以下优先级比较的表格:

运算符,c 表示当前读入运算符,对于当前运算符是否入栈,进行如下操作: 比较当前运算符和栈顶运算符的优先级的大小:

1、如果当前运算符的优先级大于栈顶运算符的优先级,即op

2、如果当前运算符的优先级小于栈顶运算符的优先级,即op>c ;令函数返回值为'>',此时应将栈顶运算符出栈和栈顶、次栈顶操作数出栈并进行相应的运算。

3、如果当前元素的优先级等于栈顶运算符的优先级,即op=c ;令函数的返回值为'=',此时界限符内的表达式已计算完毕。 3、ADT 描述

ADT Stack{

数据对象:D={i a |i a ∈ElemSet,i=1,2,…,n, n ≧0} 数据对象:R1={<1,-i i a a >|1-i a ,D a i ∈,i=2,…,n}

约定n a 端为栈顶,i a 端为栈底。

基本操作:

InitStack(&S)

操作结果:构造一个空栈S 。 GetTop(S)

初始条件:栈S 已存在。

操作结果:用P 返回S 的栈顶元素。 Push(&S ,ch)

初始条件:栈S 已存在。

操作结果:插入元素ch 为新的栈顶元素。 Pop(&S)

初始条件:栈S 已存在。

操作结果:删除S 的栈顶元素。

In(ch)

操作结果:判断字符是否是运算符,运算符即返回1。 Precede(c1, c2)

初始条件:c1,c2为运算符。

操作结果:判断运算符优先权,返回优先权高的。

Operate(a,op,b)

初始条件:a,b 为整数,op 为运算符。

操作结果:a 与b 进行运算,op 为运算符,返回其值。

num(n)

操作结果:返回操作数的长度。

EvalExpr()

初始条件:输入表达式合法。

操作结果:返回表达式的最终结果。

}ADT Stack

4、程序模块设计

(1)程序模块

本程序主要包含3个模块:主程序模块、计算模块以及顺序栈操作模块,调用关系如图所示:

图1:程序模块图

(2)系统功能模块

本程序大致包含10个函数,其中包含主函数。每个函数都有其相对应的功能实现。

○1操作符的输入函数 int In(char c);

○2运算符比较优先级函数 char Proceed(char op,char c);

○3进行四则运算函数 int Operate(int a,char a1,int b);

○4实现表达式的求值函数 int EvalExpres(void);

○5初始化栈函数 void InitStack(Stack *s);

○6入栈函数 void Push(Stack *s, int x);

○7出栈函数 int Pop(Stack *s);

○8取栈顶元素函数 int GetTop(Stack *s) ;

○9判栈空函数 void Empty(Stack *s);

○10主函数 int main()

(3)函数之间主要调用的关系图

本程序主要包含10个程序,各程序之间的关系如图所示:(部分函数用以上的编号表示)

○1○2○3○5○6○7○8○9

图2:函数之间调用关系图

五、详细设计和编码

1、结构体类型的定义

typedef struct

{

int data[MAXSIZE];

int top; //栈顶

int base; //栈底

}Stack;

2、全局变量定义

//以下为函数声明

void InitStack(Stack *); //初始化栈

int Empty(Stack *); //判空栈

void Push(Stack *, int ); //进栈

int Pop(Stack *);//出栈

int GetTop(Stack *); //取栈顶元素

int Operate(int ,char ,int ); // 计算结果

char Proceed(char ,char ); // 比较优先级

int In(char ); //判断输入符

int EvalExpres(void); //表达式计算函数

// 定义两个栈分别存放运算符和操作数

Stack StackR,StackD;

3、系统主要子程序的详细设计

(1)主函数模块设计

int main()//主函数

{

int v;

char ch;

while (1)

{

cout << "************算术表达式求解************" << endl;

v = EvalExpres();

cout << "表达式的计算结果为:" << v << endl;

cout << "Input 'n' to quit and ENTER run again:" << endl;

do

{

cin>>ch;

if (ch == 'n' || ch == 'N')

exit(0);

} while (ch != '\n');

system("cls");

}

return 0;

}

在主函数中,设定用户操作界面的形式,通过调用表达式求解的子函数实现算法所要实现的功能,然后通过while()循环语句控制,可以实现多次调试。 (2)计算函数模块

int Operate(int a, char a1, int b)

{

int s;

int d1 = a;

int d2 = b; //把字符ab变为对应数字

switch (a1)

{

case '+':

s = d1 + d2;

break;

case '-':

s = d2 - d1;

break;

case '*':

s = d1*d2;

break;

case '/':

if (d1 != 0)

{

s = d2 / d1;

}

else

{

cout << "除数不可以为0!" << endl;

exit(0);

}

}

return (s + '0'); //将运算结果转化为ascii码的形式入栈,

}

在计算函数中,定义3个变量,表示基本运算中的变量。采用开关语句实现表达式的基本运算,将运算结果转化为ASCII的形式返回。

(3)表达式求解的函数模块

int EvalExpres(void) // 表达式求解函数

{

int a, b, i = 0, s = 0;

char c[80], r;

InitStack(&StackR);

Push(&StackR, '#');

InitStack(&StackD);

cout << "请输入表达式并以‘#’结束:" << endl;

gets(c);

while (c[i] != '#' || GetTop(&StackR) != '#')

{

if (!In(c[i])) //判断读入的字符不是运算符是则进栈

{

if (c[i] >= '0' && c[i] <= '9')

{

s += c[i] - '0'; //字符相减将字符型转化为整型

while (!In(c[++i])) //继续判断下一个字符,若不是运算符,表明为多位数,直到读取到字符为运算符为止

{

s *= 10;

s += c[i] - '0';

}

Push(&StackD, s + '0'); //将整型转化为ascii的形式入栈,使字符在栈内以ascii的形式保存,实现多位数的计算

s = 0; //初始化s,继续判断

}

else

{

cout << "你输入的表达式有误!" << endl;

exit(0);

}

}

else

switch (Proceed(GetTop(&StackR), c[i])) //此函数用来比较读取的运算符和栈顶运算符的优先级

{

case '<': //栈顶的元素优先级低,当前运算符入栈

Push(&StackR, c[i]);

i++;

break;

case '=':

Pop(&StackR);

i++;

break;

case '>': //栈顶的优先级高则出栈,并将计算结果压入栈内

r = Pop(&StackR);

a = Pop(&StackD) - '0'; //操作数在栈内以ascii的形式存储,出站后要将ascii转化为整型,然后进行运算

b = Pop(&StackD) - '0';

Push(&StackD, Operate(a, r, b));

break;

}

}

return (GetTop(&StackD) - '0'); // 将栈顶元素转化为整型的形式输出

}

对于表达式求解函数,在程序中主要思想是对读入的表达式进栈进行判断。若读入的是‘0’到‘9’之间的字符,将这些字符采用ascii相减的形式转化为

整型,再入opnd栈,若读入的字符为运算符,则将运算符入栈,并比较运算符之间的优先级,看是否运算,若栈顶的运算符小于当前输入的运算符,则不需运算,只要将当前运算符入栈即可。否则,运算。运算时先将optr栈的栈顶运算符和opnd栈的栈顶、次栈顶元素出栈,并将opnd栈中出栈的元素的ASCII形式转化为整型再计算,最后讲计算结果再转化为ASCII码的形式压入opnd栈中。使表达式求解函数返回值为opnd的栈顶元素。

六、上级调试过程

1、遇到问题以及解决方案

问题1、调试时没有错误,但运行时显示错误。

解决方案:通过它提示的错误和警告,在判断是否为运算符的子函数中出现错误,如果为运算符时返回1,其次返回0,在返回0时没有用else,这样使得整个子函数可以返回一个有效值。

问题2、调试时程序显示没有错误,可以运行,但在运行时结果却出现错误。解决方案:把程序从头看了一遍,发现在比较优先级的函数中,优先级的比较比较乱,而且部分出错,后来查了关于运算符优先级的资料,通过在纸上把各种优先级列出,解决这个错误。

2、算法的时间复杂度

由于在主函数用到嵌套循环,故算法的时间复杂度为O(n^2)。

3、测试结果及其分析

(1)实现基本的加减乘除运算,当想要继续输入表达式时点击enter键,若要结束,点击n或N键即可,而且可实现多位数的运算。

(2)实现复杂的算术表达式

(3)错误表达式的处理

4、用户使用说明

(1)本程序执行的文件为“算数表达式的求解问题”。

(2)所求表达式中都只是仅包含加、减、乘、除4种基本运算的,其中也包含括号的应用,所有的运算对象均为简单变量,要求将表达式中的数字字符转化为整型,且输入表达式以“#”结束。

(3)输入表达式时,以‘#’结束,当点击回车键时即可得到运算结果,当想继续输入表达式时,再次点击回车键即可,当想结束时,点击字母‘n’或‘N’。(4)当输入错误表达式时,程序会给出相应的提醒。

七、总结与心得

这次课程设计让我更加了解大一学到的C++和大二学到的数据结构。课设题目要求不仅要求对课本知识有较深刻的了解,同时要求程序设计者有较强的思维和动手能力和更加了解编程思想和编程技巧。

这次课程设计让我有一个深刻的体会,那就是细节决定成败,编程最需要的是严谨,如何的严谨都不过分,往往检查了半天发现错误发生在某个括号,分号,引号,或者数据类型上。就像我在写EvalExpres()函数时,忘了指针的地址符值不用加*号,这一点小小的错误也耽误了我几十分钟,所以说细节很重要。

程序设计时,也不要怕遇到错误,在实际操作过程中犯的一些错误还会有意外的收获,感觉课程设计很有意思。在具体操作中这学期所学的数据结构的理论知识得到巩固,达到课程设计的基本目的,也发现自己的不足之出,在以后的上机中应更加注意,同时发现上机的重要作用,特别算术表达式有了深刻的理解。

通过实际操作,我也发现我的好多不足之处:

(1)用栈的结构来解决表达式的求值,首先要解决的问题是如何将人们习惯书写的表达式转换成计算机容易处理的表达式。开始有些茫然,后来通过结合课本和同学的帮助完成了该课题。

(2)对一些看似简单的东西掌握不够熟练,比如由于函数的调用参数问题不熟

而造成了调试的困难。对于语法的掌握也欠缺成熟,需要进一步掌握。

(3)栈的结构理解不够清晰,造成了设计程序时理不清头绪,需要对数据结构有更深层次的理解。

八、参考文献

[1]王昆仑、李红主编,数据结构与算法,北京:中国铁道出版社,2007年5月

[2]阮宏一、鲁静主编,数据结构课程设计(C/C++描述),北京:电子工业出版社,2011年1月

[3]严蔚敏、吴伟民主编《数据结构》(C语言版)清华大学出版社 2002

[4]殷人昆等著《数据结构》(C++版)清华大学出版社 2001

附录(源程序):

#include

using namespace std;

#define MAXSIZE 16

typedef struct

{

int data[MAXSIZE];

int top;

int base; //栈底

}Stack; // 顺序栈的定义

//以下为函数声明

void InitStack(Stack *); //初始化栈

int Empty(Stack *); //判空栈

void Push(Stack *, int); //进栈

int Pop(Stack *);//出栈

int GetTop(Stack *); //取栈顶元素

int Operate(int, char, int); // 计算结果

char Proceed(char, char); // 比较优先级

int In(char); //判断输入符

int EvalExpres(void); //表达式计算函数

// 定义两个栈分别存放运算符和操作数

Stack StackR, StackD;

int main()//主函数

{

int v;

char ch;

while (1)

{

cout << "************算术表达式求解************" << endl;

v = EvalExpres();

cout << "表达式的计算结果为:" << v << endl;

cout << "Input 'n' to quit and ENTER run again:" << endl;

do

{

cin>>ch;

if (ch == 'n' || ch == 'N')

exit(0);

} while (ch != '\n');

system("cls");

}

return 0;

}

void InitStack(Stack *s) //初始化栈

{

s->top = 0;

s->base = 0;

}

int Empty(Stack *s)//判断栈是否为空

{

if (s->top == s->base)

return 1; //栈空时返回1,否则返回0

else

return 0;

}

void Push(Stack *s, int x) // 进栈

{

if (s->top == MAXSIZE)

{

cout << "error" << endl;

exit(0);

}

else

{

s->data[s->top] = x;

s->top++;

}

}

int Pop(Stack *s)// 出栈

{

int e;

if (Empty(s))

{

cout << "error" << endl;

exit(0);

}

else

{

s->top--;

e = s->data[s->top];

return e;

}

}

int GetTop(Stack *s) //取栈顶元素

{

if (Empty(s))

{

cout << "error" << endl;

exit(0);

}

else

return s->data[s->top - 1];

}

int EvalExpres(void) // 表达式求解函数

{

int a, b, i = 0, s = 0;

char c[80], r;

InitStack(&StackR);

Push(&StackR, '#');

InitStack(&StackD);

cout << "请输入表达式并以‘#’结束:" << endl;

gets(c);

while (c[i] != '#' || GetTop(&StackR) != '#')

{

if (!In(c[i])) //判断读入的字符不是运算符是则进栈

{

if (c[i] >= '0' && c[i] <= '9')

{

s += c[i] - '0'; //字符相减将字符型转化为整型

while (!In(c[++i])) //继续判断下一个字符,若不是运算符,表明为多位数,直到读取到字符为运算符为止

{

s *= 10;

s += c[i] - '0';

}

Push(&StackD, s + '0'); //将整型转化为ascii的形式入栈,使字符在栈内以ascii的形式保存,实现多位数的计算

s = 0; //初始化s,继续判断

}

else

{

cout << "你输入的表达式有误!" << endl;

exit(0);

}

}

else

switch (Proceed(GetTop(&StackR), c[i])) //此函数用来比较读取的运算符和栈顶运算符的优先级

{

case '<': //栈顶的元素优先级低,当前运算符入栈

Push(&StackR, c[i]);

i++;

break;

case '=':

Pop(&StackR);

i++;

break;

case '>': //栈顶的优先级高则出栈,并将计算结果压入栈内

r = Pop(&StackR);

a = Pop(&StackD) - '0'; //操作数在栈内以ascii的形式存储,出站后要将ascii转化为整型,然后进行运算

b = Pop(&StackD) - '0';

Push(&StackD, Operate(a, r, b));

break;

}

}

return (GetTop(&StackD) - '0'); // 将栈顶元素转化为整型的形式输出

}

int In(char c) //判断C是否为运算符是返回1否则返回0

{

char ch[7] = { '+', '-', '*', '/', '#', '(', ')' };

int i;

for (i = 0; i < 7; i++)

if (c == ch[i])

return 1;

return 0;

}

char Proceed(char op, char c) //op为栈顶元素,c为当前读入的运算符,比较二者的优先级

{

char ch;

if (op == '(' && c == ')' || op == '#' && c == '#')

ch = '=';

else if (op == '+' || op == '-') /*栈顶元素为‘+’或‘-’的时候*/

switch (c)

{

case '+':

case '-':

case ')':

case '#': ch = '>'; break;

case '*':

case '/':

case '(': ch = '<';

}

else if (op == '*' || op == '/') /*栈顶元素为‘*’或‘/’的时候*/

switch (c)

{

case '+':

case '-':

case '*':

case '/':

case ')':

case '#': ch = '>'; break;

case '(': ch = '<';

}

else if (op == '(') /*栈顶元素为‘(’的时候*/ switch (c)

{

case '+':

case '-':

case '*':

case '/':

case '(': ch = '<'; break;

case '#':

cout << "Error!没有右括号!" << endl;

exit(0);

}

else if (op == ')') //栈顶元素为‘)’的时候

switch (c)

{

case '+':

case '-':

case '*':

case '/':

case '#': ch = '>'; break;

case '(':

cout << "Error!括号匹配错误!" << endl;

exit(0);

}

else if (op == '#') //栈顶元素为‘#’的时候switch (c)

{

case '+':

case '-':

case '*':

case '/':

case '(': ch = '<'; break;

case ')':

cout << "Error!没有左括号!" << endl;

exit(0);

}

return ch;

}

int Operate(int a, char a1, int b)

{

int s;

int d1 = a;

int d2 = b; //把字符ab变为对应数字

switch (a1)

{

case '+':

s = d1 + d2;

break;

case '-':

s = d2 - d1;

break;

case '*':

s = d1*d2;

break;

case '/':

if (d1 != 0)

{

s = d2 / d1;

}

else

{

cout << "除数不可以为0!" << endl;

exit(0);

}

}

return (s + '0'); //将运算结果转化为ascii码的形式入栈,}

车厢调度

一、问题陈述

假设停在铁路调度站入口处的车厢序列的编号一次为1,2,3,4。设计一个程序,求出所有可能由此输出的长度为4的车厢序列。

二、问题分析与设计

车厢调度问题是实际生活中的一个抽象问题,实际上其本质就是一个N个数的全排列问题,所谓全排列算法就是对于给定的字符集,用有效的方法将所有可能的全排列无重复无遗漏地枚举出来。

N个字符的全体排列之间存在一个确定的线性顺序关系。所有的排列中除最后一个排列外,都有一个后继;除第一个排列外都有一个前驱。每一个排列的后继都可以从它的前驱经过最少的变化得到,全排列的生产算法就是从第一个排列开始逐个生产所有的排列的方法。

全排列的生产法通常有几下几种:

字典排序法:从右往左开始找出第一个比右边数字小的数字的序号j,然后在以j为基准再从左往右,找出第一个比它大的最小的数,然后这两个数位置对调。例如:1 5 4 7 6 32 的下一个排列是 1 56 74 3 2 。

邻位交换法:邻位对换法中下一个排列总是上一个排列某相邻两位对换得到的。例如:以4个元素的排列为例,将最后的元素4逐次与前面的元素交换,可以生成4个新排列:1 2 3 4、1 243、14 2 3、4 1 2 3。然后将最后一个排列的末尾的两个元素交换,再逐次将排头的4与其后的元素交换,又生成四个新排列:4 13 2、143 2、1 3 4 2、1 3 2 4。再将最后一个排列的排头的两个元素交换,再将4从后往前移:3 1 2 4、3 14 2、34 1 2、4 3 1 2。如此循环既可求出全部排列。

递归类算法:我将选择递归类算法作为实现该车厢调度的主要算法,通过设计perm递归函数。

三、运行结果

当列车长度为4时:

算术表达式的求解-数据结构课程设计报告

课程设计报告 题目:算术表达式求值 一、需求分析 1、设计要求: 给定一个算术表达式,通过程序求出最后的结果 1>、从键盘输入要求解的算术表达式; 2>、采用栈结构进行算术表达式的求解过程; 3>、能够判断算术表达式正确与否; 4>、对于错误表达式给出提示; 5>、对于正确的表达式给出最后的结果; 2、设计构想: 为了实现算符优先算法使用两个工作栈,一个称作OPTR,以寄存运算符;另一个称作OPND,用以寄存操作数或运算结果。在操作数和操作符入栈前,通过一个函数来判别,输入的是操作数还是操作符,操作数入OPND,操作符入OPTR。在输入表达式的最后输入‘#’,设定‘#’的优先级最低,代表表达式输入结束。在表达式输入过程中,遇操作数则直接入栈,遇到运算符则与栈顶运算符比较优先级,若当前运算符优先级高,则当前运算符入栈,扫描下一符号;否则栈顶运算符出栈,两操作数出栈,进行运算,所得结果入数栈,重新比较当前运算符与新栈顶运算符。如此重复直到栈顶运算符与当前符号均为‘#’,运算结束。 二、概要设计 1、本程序包含的模块:

(1)栈模块——实现栈抽象数据类型 (2)运算模块——实现数据表达式的运算(3)主程序模块 三、详细设计 (1)栈模块 1、定义栈结构 struct Sqstack

{ elemtype *top;//栈顶元素 elemtype *base; //栈底元素 int stacksize;//栈的大小 }; 2、栈的基本操作 ①初始化栈 status initstack(struct Sqstack &s) { s.base=(elemtype *)malloc(stack_size*sizeof(elemtype)); if(!s.base) return OVERFLOW; s.top=s.base; s.stacksize=stack_size; return OK; } ②入栈 status push(struct Sqstack &s,elemtype e) {

数据结构表达式求值实验报告

竭诚为您提供优质文档/双击可除数据结构表达式求值实验报告 篇一:数据结构实验二——算术表达式求值实验报告 《数据结构与数据库》 实验报告 实验题目算术表达式求值 学院:化学与材料科学学院 专业班级:09级材料科学与工程系pb0920603 姓学 邮名:李维谷号:pb09206285箱: liwg@https://www.360docs.net/doc/667596143.html,指导教师:贾伯琪 实验时间:20XX年10月10日 一、需要分析 问题描述: 表达式计算是实现程序设计语言的基本问题之一,它的实现是栈的应用的一个典型例子。设计一个程序,演示通过将数学表达式字符串转化为后缀表达式,并通过后缀表达式结合栈的应用实现对算术表达式进行四则混合运算。

问题分析: 在计算机中,算术表达式由常量、变量、运算符和括号组成。由于不同的运算符具有不同的优先级,又要考虑括号,因此,算术表达式的求值不可能严格地从左到右进行。因而在程序设计时,借助栈实现。 设置运算符栈(字符型)和运算数栈(浮点型)辅助分析算符优先关系。在读入表达式的字符序列的同时完成运算符和运算数的识别处理,然后进行运算数的数值转换在进行四则运算。 在运算之后输出正确运算结果,输入表达式后演示在求值中运算数栈内的栈顶数据变化过程,最后得到运算结果。 算法规定: 输入形式:一个(:数据结构表达式求值实验报告)算术表达式,由常量、变量、运算符和括号组成(以字符串形式输入)。为使实验更完善,允许操作数为实数,操作符为(、)、.(表示小数点)、+、-、*、/、^(表示乘方),用#表示结束。 输出形式:演示表达式运算的中间结果和整个表达式的最终结果,以浮点型输出。 程序功能:对实数内的加减乘除乘方运算能正确的运算出结果,并能正确对错误输入和无定义的运算报错,能连续测试多组数据。 测试数据:正确输入:12*(3.6/3+4^2-1)#

muParse和MTParse两种数学表达式解析器的比较

muParse和MTParse两种数学表达式解析器的比较 muParse小巧精干,提供LIB、DLL及源代码引入方式,与其说是C++风格的,实际上更贴切的说应该是C风格的,虽然同时支持C风格和C++类两种编码样式,但C++实现貌似只是做了一层简单的封装而已,也就说和C方式一样,都是用回调函数形式实现句法操作符和函数的扩展,而且C++调用接口很大程度上依赖于STL库。同样由于它使用了纯粹C代码实现,而且首次使用后使用的都是二进制调用,所以它的最大优点是速度较快,更适合于实时性要求较高的环境,如Unix系统和单片机环境。 MTParser优雅简洁,提供LIB、COM、源代码三种引入方式,是用典型的C++风格编写的解析器,和muParser不同,它引入多种设计模式,使用C++类接口继承的方式供扩展句法操作符及函数,因而可扩展性和可维护性都很强,而且像文中所标榜的一样,它的最大特点是支持动态运行时插件扩展,从而实现发布后无需编译宿主程序只需替换插件实现表达式函数功能更新。另外,它还提供了宽窄字符两种LIB库,理论上VC各版本应该均能兼容,还有一个特点就是它的多语言本地化支持,和插件配置一样,可以通过配置XML文档对操作函数、异常描述等信息实现多种语言配置和切换。但是,和muParse相比,它的速度并不是优势,如作者所说,速度并不是MTParse最优先考虑的,也许文中所说的可扩展、可维护、易于使用、健壮性才是它的最大优势。 综合比较,如果对于速度要求不是非常之高,而且基本上都只是在Windows下多个VC版本间进行切换,而且如果还打算提供多语言支持,那么建议使用MTParse解析器。首先,muParse支持的基本功能MTParse似乎大都支持,有些MTParse支持的功能muParse反而不支持。其次,虽说做同样的操作符扩展工作,muParse也许能使用更少的代码实现,但是回调函数调多了就乱了,实在不如接口继承的方式优雅而易于维护,而且个人认为MTParse确实也多不了多少编码量,也许通过一定的再次提取封装

算术表达式求值演示程序

数理学院 课程设计报告书 课程名称数据结构课程设计 设计题目算术表达式求值演示 专业班级 学号 姓名 指导教师

2014 年12 月

4.2.2 基本操作: InitStack(&S) 操作结果:构造一个空栈S。 GetTop(S) 初始条件:栈S 已存在。 操作结 果: 用P 返回S的栈顶元素。Push(&S 初始条 件:,ch) 栈S 已存在。 操作结 果:插入元素ch 为新的栈顶元素。 Pop(&S) 初始条件:栈S 已存在。 操作结 果:删除S 的栈顶元素。 In(ch) 操作结果:判断字符是否是运算符,运算符即返回1 Precede(c1, c2) 初始条件:c1,c2 为运算符。操作结果:判断运算符优先权,返回优先权高的。Operate(a,op,b) 初始条件:a,b 为整数,op为运算符。操作结果: a 与 b 进行运算,op 为运算符,返回其值。num(n) 操作结果:返回操作数的长度。EvalExpr() 初始条件:输入表达式合法。操作结果:返回表达式的最终结果。}ADT Stack 主程序的流程:

EvaluateExpression() 函数实现了对表达式求值的功能,main() 函数直接调用EvaluateExpression() 对输入的表达式求值输出。 4.2.3 函数的调用关系图

4.3 详细设计 4.3.1 ① . Precede(char c1,char c2)判断运算符优先权,返回优先权高的 算符间的优先关系 如下: 算法伪代码如下: char Precede(char c1,char c2) { static char array[49]={ >', '>', '<', '<', '<', '>', '>', >', '>', '<', '<', '<', '>', '>', >', '>', '>', '>', '<', '>', '>', >', '>', '>', '>', '<', '>', '>', <', '<', '<', '<', '<', '=', '!', >', '>', '>', '>', '!', '>', '>', <', '<', '<', '<', '<', '!', '='}; // 用一维数组存储 49 种情况 switch(c1) { /* i 为下面 array 的横标 */ case '+' : i=0;break; case '-' : i=1;break; case '*' : i=2;break;

数据结构实验二——算术表达式求值实验报告

《数据结构与数据库》 实验报告 实验题目 算术表达式求值 学院:化学与材料科学学院 专业班级:09级材料科学与工程系PB0920603 姓名:李维谷 学号:PB09206285 邮箱:liwg@https://www.360docs.net/doc/667596143.html, 指导教师:贾伯琪 实验时间:2010年10月10日 一、需要分析 问题描述:

表达式计算是实现程序设计语言的基本问题之一,它的实现是栈的应用的一个典型例子。设计一个程序,演示通过将数学表达式字符串转化为后缀表达式,并通过后缀表达式结合栈的应用实现对算术表达式进行四则混合运算。 问题分析: 在计算机中,算术表达式由常量、变量、运算符和括号组成。由于不同的运算符具有不同的优先级,又要考虑括号,因此,算术表达式的求值不可能严格地从左到右进行。因而在程序设计时,借助栈实现。 设置运算符栈(字符型)和运算数栈(浮点型)辅助分析算符优先关系。在读入表达式的字符序列的同时完成运算符和运算数的识别处理,然后进行运算数的数值转换在进行四则运算。 在运算之后输出正确运算结果,输入表达式后演示在求值中运算数栈内的栈顶数据变化过程,最后得到运算结果。 算法规定: 输入形式:一个算术表达式,由常量、变量、运算符和括号组成(以字符串形式输入)。为使实验更完善,允许操作数为实数,操作符为(、)、.(表示小数点)、+、-、*、/、^(表示乘方),用#表示结束。 输出形式:演示表达式运算的中间结果和整个表达式的最终结果,以浮点型输出。 程序功能:对实数内的加减乘除乘方运算能正确的运算出结果,并能正确对错误输入和无定义的运算报错,能连续测试多组数据。 测试数据:正确输入:12*(3.6/3+4^2-1)# 输出结果:194.4

编译原理 语法分析器 (java完美运行版)

实验二语法分析器 一、实验目的 通过完成预测分析法的语法分析程序,了解预测分析法和递归子程序法的区别和联系。使学生了解语法分析的功能,掌握语法分析程序设计的原理和构造方法,训练学生掌握开发应用程序的基本方法。有利于提高学生的专业素质,为培养适应社会多方面需要的能力。 二、实验内容 ◆根据某一文法编制调试LL (1 )分析程序,以便对任意输入的符号串 进行分析。 ◆构造预测分析表,并利用分析表和一个栈来实现对上述程序设计语言的分 析程序。 ◆分析法的功能是利用LL(1)控制程序根据显示栈栈顶内容、向前看符号 以及LL(1)分析表,对输入符号串自上而下的分析过程。 三、LL(1)分析法实验设计思想及算法 ◆模块结构: (1)定义部分:定义常量、变量、数据结构。 (2)初始化:设立LL(1)分析表、初始化变量空间(包括堆栈、结构体、数组、临时变量等); (3)控制部分:从键盘输入一个表达式符号串; (4)利用LL(1)分析算法进行表达式处理:根据LL(1)分析表对表达式符号串进行堆栈(或其他)操作,输出分析结果,如果遇到错误则显示错误信息。

四、实验要求 1、编程时注意编程风格:空行的使用、注释的使用、缩进的使用等。 2、如果遇到错误的表达式,应输出错误提示信息。 3、对下列文法,用LL(1)分析法对任意输入的符号串进行分析:(1)E->TG (2)G->+TG|—TG (3)G->ε (4)T->FS (5)S->*FS|/FS (6)S->ε (7)F->(E) (8)F->i 输出的格式如下:

五、实验源程序 LL1.java import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.table.DefaultTableModel; import java.sql.*; import java.util.Vector; public class LL1 extends JFrame implements ActionListener { /** * */ private static final long serialVersionUID = 1L; JTextField tf1; JTextField tf2; JLabel l; JButton b0; JPanel p1,p2,p3; JTextArea t1,t2,t3; JButton b1,b2,b3;

数据结构算术表达式求值实验报告

软件技术基础实验报告 实验名称:表达式计算器 系别:通信工程 年级: 班级: 学生学号: 学生姓名: 《数据结构》课程设计报告 题目简易计算表达式的演示 【题目要求】 要求:实现基本表达式计算的功能 输入:数学表达式,表达式由整数和“+”、“-”、“×”、“/”、“(”、“)”组成输出:表达式的值 基本操作:键入表达式,开始计算,计算过程和结果记录在文档中 难点:括号的处理、乘除的优先级高于加减

1.前言 在计算机中,算术表达式由常量、变量、运算符和括号组成。由于不同的运算符具有不同的优先级,又要考虑括号,因此,算术表达式的求值不可能严格地从左到右进行。因而在程序设计时,借助栈实现。 算法输入:一个算术表达式,由常量、变量、运算符和括号组成(以字符串形式输入)。为简化,规定操作数只能为正整数,操作符为+、-*、/、=,用#表示结束。 算法输出:表达式运算结果。 算法要点:设置运算符栈和运算数栈辅助分析算符优先关系。在读入表达式的字符序列的同时,完成运算符和运算数的识别处理,以及相应运算。 2.概要设计 2.1 数据结构设计 任何一个表达式都是由操作符,运算符和界限符组成的。我们分别用顺序栈来寄存表达式的操作数和运算符。栈是限定于紧仅在表尾进行插入或删除操作的线性表。顺序栈的存储结构是利用一组连续的存储单元依次存放自栈底到栈顶的数据元素,同时附设指针top 指示栈顶元素在顺序栈中的位置,base 为栈底指针,在顺序栈中,它始终指向栈底,即top=base 可作为栈空的标记,每当插入新的栈顶元素时,指针top 增1,删除栈顶元素时,指针top 减1。 2.2 算法设计 为了实现算符优先算法。可以使用两个工作栈。一个称为OPTR ,用以寄存运算符,另一个称做OPND ,用以寄存操作数或运算结果。 1.首先置操作数栈为空栈,表达式起始符”#”为运算符栈的栈底元素; 2.依次读入表达式,若是操作符即进OPND 栈,若是运算符则和OPTR 栈的栈顶运算符比较优先权后作相应的操作,直至整个表达式求值完毕(即OPTR 栈的栈顶元素和当前读入的字符均为”#”)。 2.3 ADT 描述 ADT Stack{ 数据对象:D={ i a |i a ∈ElemSet,i=1,2,…,n, n ≧0} 数据对象:R1={< 1 ,-i i a a >| 1-i a ,D a i ∈,i=2,…,n}

词法分析器的设计与实现

目录 一.设计题目 (2) 二.设计要求 (2) 1. 词法分析器的定义 (2) 2. 设计要求 (2) 3. 本程序自行规定: (3) 三.设计作用与目的 (4) 1. 设计作用 (4) 2. 设计目的 (4) 四.运行环境及工具软件 (4) 五.系统设计 (5) 1. 系统总体设计 (5) (1)词法分析器的设计 (5) (2)总体设计框图 (6) (3)总程序流程图 (6) 2. 各子模块设计 (8) (1)字符的识别 (8) (2)关键字的识别 (8) (3)数字的识别 (8) (4)界符的识别 (10) (5)运算处理 (10) 3.相关函数分析 (11) 4. 源程序设计 (12) 六.实验调试结果 (29) 1. 调试工具 (29) 2. 调试步骤 (29) 3. 调试结果 (29) 七.设计中的问题及解决方法 (31) 八.设计心得 (32) 九.参考文献 (34)

词法分析器的设计与实现 一.设计题目 词法分析器的设计与实现 二.设计要求 1. 词法分析器的定义 词法分析顾名思义就是分词。它以程序设计语言编制的源程序作为输入,以单词序列作为输出。分词过程可以通过编制程序自动完成,我们通常称这个分词程序为词法分析器。词法分析器分析的源程序可以是现有的各类程序设计语言源程序也可以是人为给定的模型语言的源程序。本文中的源程序为后者。从词的角度来看,它涉及的内容较为简单,只包括几个较为常用的词类,词类的构成上也适当的作了一些简化。对词进行分析时,我们是按类型进行分析的。不同类型的词在后续的分析中所起的作用不同,相应的操作也各有不同,但同种类型中的词虽然单词的构成不同但从宏观上看它们的操作大体一致。模型语言中的单词可以分为“关键字”、“标识符”、“常数”、“分隔符”、“运算符”几类。一般,关键字在程序设计语言中人为给定 2. 设计要求 对给定的程序通过词法分析器能够识别一个个单词符号,并以二元式(单词种别码,单词符号的属性值)显示。而本程序则是通过对给定路径的文件的分析后以单词符号和文字提示显示。另外,如果是算术表达式,则需要通过栈、运算符的优先级比较处理等从而计算出最终结果并显示。通过此次课程设计要求掌握从源程序文件中读取有效字符的方法,掌握词法分析的实现方法并上机调试编出的词法分析程序。 在处理表达式前,首先设置两个栈:一是运算符栈,用于在表达式处理过程中存放运算符。在开始时,运算符栈中先压入一个表达式结束符“#”。二是操作数栈,用于在表达式处理过程中存放操作数。然后从左到右依次读出表达式中的各个符号(运算符或操作数),每读出一个符号按以下原则进行处理:

复合算术运算符解读

复合算术运算符 现在我们来看看由几种运算符和包含混合数据类型的更复杂的表达式。 优先权规则 算术表达式能够由许多常量、变量、运算符和括号组成,那么操作执行的次序是怎样的呢?例如,在赋值语句中 avgTemp = FREEZE_PT + BOIL_PT / 2.0; 是FREEZE_PT + BOIL_PT 首先被计算呢还是 BOIL_PT / 2.0首先被计算? 基本的算术运算符的运算顺序与数学的运算符顺序是一样的,按照优先权规则: 最高优先级: 单目 + 单目 - 中等优先级: * / % 最低优先级: + - 在上面的表达式例子中隐含着用括号一样: FREEZE_PT + (BOIL_PT / 2.0 即,我们首先用2除 BOIL_PT然后加FREEZE_PT得到结果。 你能够使用括号改变求值的次序,在语句 avgTemp = (FREEZE_PT + BOIL_PT / 2.0; 中FREEZE_PT 和 BOIL_PT 首先被加,然后它们的和再除以2。我们首先求括号内的子表达式的值,然后接下来再按运算符的优先权规则求值。 当一个算术表达式有几个具有同样优先权的双目运算符时,它们的结合次序是从左到右。表达式

int1 - int2 + int3 意味着(intl - int2 + int3, 不是 int1 - (int2 + int3。另一个例子,我们使用表达式 (float1 + float2 / float1 * 3.0 首先求括号内的表达式的值,然后将得到的和除以float1再乘以3.0。下面是更多的一些例子。———————————————————— 表达式值 10/2*3 15 10%3-4/2 -1 5.0*2.0/4.0*2.0 5.0 5.0*2.0/(4.O*2.O 1.25 5.0+2.0/(4.0*2.0 5.25 ———————————————————— 在C++中, 所有的单目运算符都有从右到左的结合性,例如, - + x 意味着 - (+ x 而不是意味着(- + x。 类型的强制和类型的转换 整型值和浮点值被不同的存储在计算机存储器内,如果在一条赋值语句或算术表达式中我们将整数和浮点值混合在一起会发生什么情况?让我们首先看看赋值语句。 赋值语句如果你做如下声明 int someInt ;

AE表达式详解

AE表达式详解 今天准备抽点时间来讲一下表达式,百度了一下,表达式方面的教程比较少,视频教程有琳达的和frak的,不过都是国外的,有中文字幕。国内的视频教程有罡渡晨星的,不过要给钱才能看,我没有给,所以我不知道他讲得怎么样。至于那两个国外的教程,我觉得讲得不错,Frank的讲得比较深入,而琳达的讲得比较全一些,不过还是有一些许地方没有涉及到,文字方面的教程往往比较支离破碎,言此失彼,不够系统。所以我决定开一个帖子作一些抛砖引玉性质的讲解,可能会比较长,也许词不达意,难免有错误,希望吧友不吝海涵。 在正式接入正题之前,先了解一些基本的问题。 一、表达式能干什么, 答:表达式并不能帮你做出华丽的特效,但是可以让一些看起来比较麻烦的事情变得比较轻松,比如说你想做两个圆球的动画,并且保证两个圆球的大小无论如何变化,它们的面积之和始终是一个定值。或者一个球在做不规则移动的时候,它的周长刚好是它运动路程的三分之一。

二、表达式难学不, 答:在学之前,我也有这样的疑问,但学完之后,我才发现我完全多虑了。 三、表达式需要掌握哪些知识, 答:1、英语。英语好一点,你可以更明白你在做的是什么事情。 2、数学,主要是函数、几何方面的东西。它能告诉你怎样达到你所要的结果。 3、JAVA编程基础。你只需要懂一点点基础就可以,不必像程序员一样,这有助于你写出更规范的东西,减少出错的可能。 4、AE基础知识。这能够让你的表达式发挥得淋漓尽致。 下面说一些基本的问题 一、怎样添加表达式, 答:按ALT SHIFT 和等号键,也可以直接接ALT再点码表,如果你喜欢,你也可以在菜单的动画列表下找到它。如果你要临时禁用它,请点击=图标二、写表达式要注意什么, 1、表达式是区分大小写的,比如:LOVE和LOVe,会被认为是两个东西。 2、写之前,确认你用的是英文输入法,比如一些中文标点,是不被认可的。 3、尽量写英文,这样会让你的表达式和脚本更好地兼容,同时也更美观,更重要的是,这样逼格更高一些。 4、表达式是忽略空格和换行的,当然你也可以用空格和换行,这样会更方便你阅读。 5、表达式写完一句话,末尾用分号隔开,否则会被认为后面的内容是接着前面写的。 这四个按钮是什么鬼, 答:等号,可以临时启用或者禁用表达式

算术表达式与二叉树

目录 一、系统开发的背景 (1) 二、系统分析与设计 (1) (一)系统功能要求 (1) (二)系统模块结构设计 (1) 三、系统的设计与实现 (3) (一)二叉树的遍历 (3) (二)算术表达式求值 (5) 四、系统测试 (9) (一)测试二叉树遍历函数 (9) (二)测试算术表达式求值函数 (10) 五、总结 (10) 六、附件(代码、部分图表) (10) (一)程序代码 (10) (二)实验截图 (15)

算术表达式与二叉树 一、系统开发的背景 为了方便进行基本的算术运算,减轻对数字较大的数操作时所带来的麻烦,及其在运算过程中错误的避免。因此设计算术表达式与二叉树的程序来解决此问题。 二、系统分析与设计 (一)系统功能要求 由于一个表达式和一棵二叉树之间,存在着自然的对应关系。遍写一个程序,实现基于二叉树表示的算术表达式的操作。算术表达式内可以含有变量(a~z)、常量(0~9)和二元运算符(+,-,*,/,^(乘幂))。 具体实现以下操作: 1以字符序列的形式输入语法正确的前缀表达式并构造表达式。 2用带括弧的中缀表达式输出表达式。 3实现对变量V的赋值(V=c),变量的初值为0。 4对算术表达式E求值。 (二)系统模块结构设计 通过对系统功能的分析,基于二叉树表示的算术表达式的功能 如图(1)所示。

图1:基于二叉树表示的算术表达式的功能图 通过上图的功能分析,把整个系统划分为主要的两大个模块: 1、将语法正确的前缀表达式用二叉树的遍历转换成相应的遍历序列,必要时可以求出此二叉树的结点数及其树的深度。该模块借助函数BiTree Create(BiTree T)创建二叉树,void Preorder(BiTree T) 先序遍历, void InOrder(BiTree T)中序遍历,void PostOrder(BiTree T)后序遍历,int Sumleaf(BiTree T)统计叶结点的数目,int Depth(BiTree T)二叉树的深度6个函数联合来实现; 2、计算中序遍历所得的算术表达式的值。其中先要将扫描得到的中缀表达式转换为后缀表达式,然后利用栈的初始化,进栈与取栈顶元素操作进行对后缀表达式进行计算。该模块借助函数void InitStack(SeqStack *S)初始化栈,int PushStack(SeqStack *S,char e)进栈,int GetTop(SeqStack

编译原理实验报告(词法分析器语法分析器)

编译原理实验报告

实验一 一、实验名称:词法分析器的设计 二、实验目的:1,词法分析器能够识别简单语言的单词符号 2,识别出并输出简单语言的基本字.标示符.无符号整数.运算符.和界符。 三、实验要求:给出一个简单语言单词符号的种别编码词法分析器 四、实验原理: 1、词法分析程序的算法思想 算法的基本任务是从字符串表示的源程序中识别出具有独立意义的单词符号,其基本思想是根据扫描到单词符号的第一个字符的种类,拼出相应的单词符号。 2、程序流程图 (1 (2)扫描子程序

3

五、实验内容: 1、实验分析 编写程序时,先定义几个全局变量a[]、token[](均为字符串数组),c,s( char型),i,j,k(int型),a[]用来存放输入的字符串,token[]另一个则用来帮助识别单词符号,s用来表示正在分析的字符。字符串输入之后,逐个分析输入字符,判断其是否‘#’,若是表示字符串输入分析完毕,结束分析程序,若否则通过int digit(char c)、int letter(char c)判断其是数字,字符还是算术符,分别为用以判断数字或字符的情况,算术符的判断可以在switch语句中进行,还要通过函数int lookup(char token[])来判断标识符和保留字。 2 实验词法分析器源程序: #include #include #include int i,j,k; char c,s,a[20],token[20]={'0'}; int letter(char s){ if((s>=97)&&(s<=122)) return(1); else return(0); } int digit(char s){ if((s>=48)&&(s<=57)) return(1); else return(0); } void get(){ s=a[i]; i=i+1; } void retract(){ i=i-1; } int lookup(char token[20]){ if(strcmp(token,"while")==0) return(1); else if(strcmp(token,"if")==0) return(2); else if(strcmp(token,"else")==0) return(3); else if(strcmp(token,"switch")==0) return(4); else if(strcmp(token,"case")==0) return(5); else return(0); } void main() { printf("please input string :\n"); i=0; do{i=i+1; scanf("%c",&a[i]);

最新数学表达式计算(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栈。继续扫描直到遇到str中的结束字符\0,扫描结束。此时看操作符栈是否为空,若不为空,出栈,再从值栈中取出两个数值进行计算,将其结果存入值栈,一直进行此操作,直到操作符栈为空。此时把值栈中的数值取出,即为所得的最终计算结果。 二、算法流程图 第一种算法:中缀转后缀算法

编译原理语法分析 算术表达式

package语法分析; public class displymain { public static void main(String args[]) { new frame(); } } package 语法分析; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.*; public class frame implements ActionListener{ JFrame frame1; JLabel L1,L2; JButton bt,bt2; JTextField input,result; top_down_grammar a =new top_down_grammar(); public frame() { frame1=new JFrame(""); input=new JTextField(20); result=new JTextField(20); L1=new JLabel("请输入表达式以#结束"); L2=new JLabel("结果是:"); bt=new JButton("语法分析"); bt2=new JButton("关闭"); frame1.setTitle("递归下降子程序分析语法"); frame1.setLayout(new GridLayout(3,1)); frame1.add(L1); frame1.add(input); frame1.add(L2); frame1.add(result); frame1.add(bt); frame1.add(bt2); bt.addActionListener(this); bt2.addActionListener(this); frame1.setSize(500, 500); frame1.setVisible(true); } public void actionPerformed(ActionEvent e) { a.i=0; a.x.str=input.getText();

算术表达式求值课程设计报告

课程设计 教学院 课程名称 题目 专业 班级 姓名 同组人员 指导教师 2013 年 6 月22 日 (完成时间)

目录 一.概述 (2) 二.总体方案设计 (4) 三.详细设计 (6) 四.程序的调试与运行结果说明 (14) 五.课程设计总结 (14) 六.附录 (16) 参考文献 (3233) (“目录”要求必须自动生成)

一概述(宋体,三号,加粗,居中) 1.课程设计的目的(小标题,宋体,四号,加粗,左对齐顶格) (1).理解和掌握该课程中的有关基本概念,程序设计思想和方法。 (2).培养综合运用所学知识独立完成课题的能力。 (3).培养勇于探索、严谨推理、实事求是、有错必改,用实践来检验理论,全方位考虑问题等科学技术人员应具有的素质。 (4).掌握从资料文献、科学实验中获得知识的能力,提高学生从别人经验中找到解决问题的新途径的悟性,初步培养工程意识和创新能力。 2.课程设计的要求 算术表达式求值程序实现以下功能: (1)构造一个空栈S,初始条件:栈S已存在 (2)用P返回S的栈顶元素 (3)插入元素ch为新的栈顶元素 (4)删除S的栈顶元素 (5)判断字符是否是运算符,运算符即返回1 (6)判断运算符优先权,返回优先权高的 (7)输入表达式 (8)返回表达式的最终结果。

二总体方案设计 a)需求分析 该程序能实现算术四则运算表达式的求值,显示运算过程。 输入的形式:表达式,例如5*(3+7)#。 包含的运算符只能有'+'、 '-'、'*'、 '/'、 ' (' ') '; 程序所能达到的功能:对表达式求值并输出。 b)总体设计 本程序使用的是编程工具是Visual c++ 6.0,实现了运算器的功能和仿真界面(大体界面如下图所示)。在基本要求的基础上,运算数可以是实数类型,同时增加了乘方运算的功能;可以实现对负数的运算,例如用户输入表达式6* (-0.25),则程序会在负号的前面自动加上一个0。 1)算符包括加(+)、减(-)、乘(*)、除(/)、乘方(^);另一个称作 OPND,用以寄存操作数和运算结果,操作数可以是float型的浮点数。 算法的基本思想是: 2)首先置操作数栈为空栈,表达式起始符“#”为运算符栈的栈底元素; 依次读入表达式中的每个字符,若是操作数(浮点数)则进OPND栈, 若是运算符(+、—、*、/、^)则和OPTR栈的栈顶运算符比较优先权 后作相应操作,直至整个表达式求值完毕(即OPTR栈的栈顶元素和当 前读入的字符均为“#”)。 3)编写一个原型为void strtofloat(char str[ ],int n,int i),把一 个数字串转换为一个实型数,并压入运算数栈中。(整个程序的源代码 见附录,并有具体解释)

面向对象的表达式解析算法框架研究与实现

现代计算机(总第三一七期 面向对象的表达式解析算法框架研究与实现 孙高飞 , 王瑞平 (安阳工学院计算机科学与信息工程系,安阳45500) 摘 要:关键词:表达式解析;类工厂;全定制;解耦 收稿日期:2009-08-04 修稿日期:2009-09-01 作者简介:孙高飞(1975-),男,硕士,工程师,研究方向为计算机软件与理论 研究面向对象表达式解析的核心算法,并借助类工厂模式实现对表示式符号集和方法 自定义的支持。表达式解析算法支持运算符定义和重载,支持方法自定义,可以通过方法和符号集的扩展,通过配置即可构造新的表达式解析器。 0引言 实现软件模块之间、层次之间的解耦是非常重要 的软件设计准则。在耦合的四种形式中,以数据耦合的耦合程度最小。数据耦合的一种方式就是表达式,通过表达式的定制,可以实现运行期的数据动态绑定。例如:EL 表达式,在网页框架语言中广泛使用。 在应用软件中,同样对表达式解析器有非常广泛的使用。例如在工作流平台中,就需要表达式来定义表单中关联的数据。报表工具也同样使用表达式来提取外部数据,Excel 中的公式同样也是表达式。 1表达式解析器的基本原理 简单的表达式至少包含如下部分:操作数、操作 符、方法。其中括号、逗号都被视为操作符的一部分,称之为界限符。 要想正确地计算出表达式的结果,首先必须有正确的解释表达式,最为常用的方法是算符优先法,即根据运算优先关系的规定来实现对表达式的解释。对于普通的表达式,其运算规则是:先计算优先级高的运行符;计算从左到右;先计算括号内,再计算括号外。 一般的表达式解析算法都是通过栈来实现,其中一个栈寄存操作符,另一个栈来寄存操作数或计算结果。算法的基本思想是依次读入表达式中的每个字符,如果是操作数则压入操作数栈,若是操作符则和操作符栈的栈顶元素比较优先级,如果栈顶操作符的优先级低,则将新操作符入栈,否则出栈操作数,和新操作符进行计算,并将结果压入操作数栈。重复以上 操作,直至表达式求值完毕。 2定制表达式需要处理的问题 依据表达式基本原理可以用来实现简单的加减 乘除四则混合运算,但是如果想实现一个高弹性的能定制解决复杂表达式的框架,还有很多工作需要做。这些工作包括:操作符的优先级的定制、方法的定制、操作符的定制、操作数(参数)类型定制、嵌套对象的解析、解析方法的定制、定制文件解析。在以上工作全部完成后,实现的表达式框架就能够实现表达式所有元素的定制,这个框架是完全定制的,支持多种符号集的表达式解析器扩展。表达式解析框架的实现流程图如图1所示。 图1表达式解析框架的实现流程图 3定制文件 表达式解析框架的定制采用XML 文件来实现, 采用DOM 对XML 解析进行解析。XML 标准格式 DTD 文件如下:

数据结构课程设计算术表达式求值计算器.doc

高级语言程序设计 《算术表达式求值》 课程设计报告

算术表达式求值 系统可以实现实现对算术四则混合运算表达式求值,并打印求值过程中运算符栈、操作数栈的变化过程。 第二章系统分析 开始运行时界面如下: 你可以输入一个表达式,按E对其进行求值。

第四章系统实现 #include #include #include #include #define N 100 double numStack[N]={0};//操作数栈 int numTop; char opStack[N];//运算符栈 int opTop; void print_num(double str1[],int n) { int i; printf("\n操作数栈:\n"); for(i=0;i

if(ch=='+'||ch=='-') return 2; if(ch=='*'||ch=='/') return 3; if(ch=='(') return -1; return 0; } double result(double num1,char op,double num2)//计算 { if(op=='+') return num1+num2; if(op=='-') return num1-num2; if(op=='*') return num1*num2; if(op=='/') return num1/num2; return 0; } int compute(char str[]) { double num=0; int i=0,j=1,k=1; numTop=opTop=0; while(str[i]!='\0'||opTop>0) { if(str[i]>='0'&&str[i]<='9') num=num*10+str[i]-'0'; else if( k==1&&str[i]=='-'&&(i==0||op(str[i-1])) ) k=-1; else { if(i>0&&!op(str[i-1])&&str[i]!='('&&str[i-1]!=')')

数据结构算术表达式求值课程设计

目录 1.前言 (2) 2.问题描述 (3) 3.总体设计·····················································································错误!未定义书签。 3.1 概要设计 ······························································································错误!未定义书签。 3.1.1 数据结构的选择 (3) 3.1.2 相关功能函数 (3) 3.1.3 函数模块调用关系 (4) 3.2详细设计和编码 (5) 4.运行与测试 (9) 4.1 上机调试 (9) 4.2 算法时间和空间性能分析 (10) 4.3程序运行测试结果 (11) 5. 总结与心得 (13) 5.1设计中难点的总结以及其它解决方案 (13) 5.2 实验心得 (14) 6. 用户使用说明 (16) 7. 参考文献 (16) 8. 附录1(源代码清单) (16) 9. 附录2(成绩评定表) (25) 1

1.前言 课程设计是实践性教学中的一个重要环节,它以某一课程为基础,它可以涉及和课程相关的各个方面,是一门独立于课程之外的特殊课程。课程设计是让同学们对所学的课程更全面的学习和应用,理解和掌握课程的相关知识。《数据结构》是一门重要的专业基础课,是计算机理论和应用的核心基础课程。 在数据结构的学习和课程设计过程中,我发现它要求学生在数据结构的逻辑特性和物理表示、数据结构的选择和应用、算法的设计及其实现等方面,都必须加深对课程基本内容的理解。同时,在程序设计方法以及上机操作等基本技能和科学作风方面受到比较系统和严格的训练。对于我们专业来说,虽然说对技术要求不是特别高,但是在实际操作过程中,没有足够的专业知识对于编程来说是远远不可以达到要求的,所以对于这次的课程设计,我们必须要通过自己额外补充知识来完成它。 在这次的课程设计中我选择的题目是表达式的求值演示。它的基本要求是:以字符序列的形式从终端输入语法正确的,不含变量的表达式。利用算符优先关系,实现对算术四则混合运算表达式的求值,并演示在求值中运算符栈、运算数栈、输入字符和主要操作的变化过程。表达式计算是实现程序设计语言的基本问题之一,也是栈的应用的一个典型例子。设计一个程序,演示用算符优先法对算术表达式求值的过程。深入了解栈和队列的特性,以便在解决实际问题中灵活运用它们,同时加深对这种结构的理解和认识。对于表示出栈在每执行一个过程中都要输出它的变化,这点我认为在编程中是比较困难的,以我自身的能力,是不可能在规定的时间内完成任务的,所以我参考了很多有价值的书籍来帮助我完成我的程序设计。 2

相关文档
最新文档