数据结构表达式的两种计算方法

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

一、设计思想

(一)先将输入的中缀表达式转为后缀再计算的设计思想

我们所熟知的计算表达式为中缀表达式,这之中包含运算符的优先级还有括号,这对我们来说已经习以为常了,但是在计算机看来,这是非常复杂的一种表达式。因此我们需要有一种更能使计算机理解的不用考虑优先级也不包括括号的表达式,也就是后缀表达式。我们可以借助栈将其实现。

首先,我们需要将中缀表达式转换为后缀表达式,这也是这个算法的关键之处。我们将创建两个栈,一个是字符型的,用来存放操作符;另一个是浮点型的,存放操作数。

接着,开始扫描输入的表达式,如果是操作数直接进入一个存放后缀表达式的数组,而操作符则按照优先级push进栈(加减为1,乘除为2),若当前操作符优先级大于栈顶操作符优先级或栈为空,push进栈,而当其优先级小于等于栈顶操作符优先级,则从栈内不断pop出操作符并进入后缀表达式数组,直到满足条件,当前操作符才能push 进栈。左括号无条件入栈,右括号不入栈,而不断从栈顶pop出操作符进入后缀表达式数组,直到遇到左括号后,将其pop出栈。这样当扫描完输入表达式并从操作符栈pop 出残余操作符后并push进栈,后缀表达式数组中存放的就是我们所需要的后缀表达式了。

扫描后缀表达式数组,若是操作数,将其转换为浮点型push进数栈;若是操作符,则连续从数栈中pop出两个数做相应运算,将结果push进数栈。当扫描完数组后,数栈顶便为最终结果,将其pop出,输出结果。

(二)一边扫描一边计算的设计思想

由于第一种算法需要进行两遍扫描,因此在性能上不会十分优秀。而此种算法只用扫描一遍,当扫描完输入的表达式后便可以直接输出最终结果。是第一种算法的改进版,性能上也得到提升,与第一种算法所不同的是其需要同时使用两个栈,一个操作符栈,一个数栈。

当扫描表达式时,若是操作数则将其转换为浮点型后直接push进数栈,而若是操作符则按照优先级规则push进操作符栈(加减为1,乘除为2),若当前操作符优先级大于栈顶操作符优先级或栈为空,push进栈,而当其优先级小于等于栈顶操作符优先级,则从栈内不断pop出操作符,直到满足条件,当前操作符才能push进栈。左括号无条件入栈,右括号不入栈,而不断从栈顶pop出操作符,直到遇到左括号后,将其pop出栈。这中间pop出操作符后直接从数栈中pop出两个数并计算,将结果push进数栈。括号的处理与第一个算法相同。

扫描完成后,从操作符栈pop出残余操作符,从数栈中pop出两个数并计算并进行计算,将结果push进数栈。数栈顶便为最终结果,将其pop出,输出结果。

两种算法各有各的优缺点,第一种算法过程比较清晰,使我们能够更加容易理解栈的使用规则,但是其性能不如第二种。第二种算法相比第一种来说性能提高了,但是理解起来就不如第一种那么清晰了。

二、算法流程图

以下是先将输入的中缀表达式转为后缀再计算算法:

图1 中缀转后缀算法流程图

以下是一边扫描一边计算算法:

图2一边扫描一边计算算法流程图三、源代码

以下为先将输入的中缀表达式转为后缀再计算算法代码:#include "stdio.h"

#include "stdlib.h"

/*定义存放操作符的结构体*/

struct OpStrack

{

char op[100];/*存放操作符的数组*/

int top;/*栈顶索引*/

int level[100];/*存放操作符优先级的数组*/

}OpStrackArray;

/*定义存放语素的结构体*/

struct OdStrack

{

float od[100];/*存放操作数的数组*/

int top;/*栈顶索引*/

}OdStrackArray;

/*声明需要用到的函数*/

int judge(char,char[],int,int);

int stackIsEmpty();

void pushOp(char,int);

char popOp();

void pushOd(float);

float popOd();

void compute(char);

/*主函数*/

void main()

{

char data[100];/*声明存放中缀表达式的字符串*/

char tempdata[200];/*声明存放后缀表达式的字符串*/

int i=0;/*作为遍历字符串的索引*/

int j=0;/*作为输出后缀表达式的索引*/

int z=0;/*作为存放后缀表达式的索引*/

int k=0;/*作为将后缀表达式赋给临时转float的索引*/

int eq=0;/*判断括号是否正确的条件*/

float result;/*声明存放最终结果的float*/

scanf("%s",data);/*输入中缀表达式*/

/*中缀转后缀,并将结果放入tempdata*/

while(data[i]!='\0')

{

if((data[i]>='0'&&data[i]<='9')||data[i]=='.')/*如果是语素则存放至temp数组*/

{

tempdata[z]=data[i];

z++;

}

else

{

switch(data[i])

{

case '+':

z+=judge(data[i],tempdata,i,1);

break;

case '-':

z+=judge(data[i],tempdata,i,1);/*加减优先级为1*/

break;

case '*':

z+=judge(data[i],tempdata,i,2);/*乘除优先级为2*/

break;

case '/':

/*返回出栈操作符的数量,以便将z索引向后推相应步*/

z+=judge(data[i],tempdata,i,2);

break;

case '(':

pushOp(data[i],-1);/*'('直接入栈,但入栈后优先级最小*/

eq++;/*有一个'('eq+1*/

break;

case ')':

while(OpStrackArray.op[OpStrackArray.top-1]!='(')/*')'不入栈*/

{

/*不断弹出操作符并进入后缀表达式数组,直到遇到'('*/

tempdata[z]=popOp();

z++;/*索引+1*/

/*如果发现还没碰到与之匹配的'('时栈已空则说明表达式不合法*/ if(stackIsEmpty()==1)

{

printf("Expression is not valid!Press any key to continue...");

getch();

return;

}

}

相关文档
最新文档