IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 表达式求值(数据结构栈c语言版) -> 正文阅读

[C++知识库]表达式求值(数据结构栈c语言版)

表达式求值(数据结构栈,c语言版)

一、实验题目

1.案例分析

任何一个表达式都是由操作数(operand)运算符(operator)和界限符(delimiter)组成的,统称它们为单词。一般地,操作数既可以是常数,也可以是被说明为变量或常量的标识符;运算符可以分为算术运算符、关系运算符和逻辑运算符 3 类;基本界限符 有左右括号和表达式结束符等。为了叙述的简洁,在此仅讨论简单算术表达式的求值问题,这种表达式只含加、减、乘、除4种运算符。读者不难将它推广到更一般的表达式上。
下面把运算符和界限符统称为算符。
我们知道,算术四则运算遵循以下 3条规则:
(1)先乘除,后加减;
(2)从左算到右;
(3)先括号内,后括号外。
根据上述 3条运算规则,在运算的每一步中,任意两个相继出现的算符θ1和θ2之间的优先关系,至多是下面 3 种关系之一 :
θ1 < θ2 θ1的优先权低于θ2
θ1 = θ2 θ1的优先权等于θ2
θ1 > θ2 θ1的优先权高于θ2
表 3.1 定义了算符之间的这种优先关系。
表3.1

由规则(1), 先进行乘除运算,后进行加减运算,所以有 “+” < “*”; “+” < “/”; “*” >"+"; “/” > “+” 等。
由规则(2), 运算遵循左结合性,当两个运算符相同时,先出现的运算符优先级高,所以有"+" > “+”; “-” > “-”; “*” > “*”; “/” > “/”。
由规则(3), 括号内的优先级高,+、-、*和/为θ1时的优先性均低千 (" “但高于 " )”。
表中的 “(” = “)” 表示当左右括号相遇时,括号内的运算已经完成。为了便千实现,假设每个表达式均以"#“开始,以”#" 结束。所以"#" = “#” 表示整个表达式求值完毕。")“与 “(”、"#”与”)" 以及"(“与”#" 之间无优先关系,这是因为表达式中不允许它们相继出现,一旦遇到这种情况,则可以认为出现了语法错误。在 下面的讨论中,我们暂假定所输人的表达式不会出现语法错误。

2.案例实现

为实现算符优先算法,可以使用两个工作栈,一个称做OPTR,用以寄存运算符;另一个称作OPND, 用以寄存操作数或运算结果。

3.算法步骤

1.初始化OPTR栈和OPND栈,将表达式起始符“#”压入OPTR栈。
2.扫描表达式,读人第一个字符ch,如果表达式没有扫描完毕至“#”或OPTR的栈顶元素不为“#”时,则循环执行以下操作:
若ch不是运算符,则压入OPND栈,读入下一字符ch;
若ch是运算符,则根据OPTR 的栈顶元素和ch的优先级比较结果,做不同的处理:
若是小于,则ch 压入OPTR栈,读入下一字符ch;
若是大于,则弹出OPTR栈顶的运算符,从 OPND栈弹出两个数,进行相应运算,结果压入OPND栈;
若是等于,则OPTR 的栈顶元素是“(”且ch是“)”,这时弹出OPTR栈顶的“(”,相当于括号匹配成功,然后读人下一字符ch。
3.OPND栈顶元素即为表达式求值结果,返回此元素。

char EvaluateExpression ()
{//算术表达式求值的算符优先算法,设OPTR和OPND分别为运算符栈和操作数栈
InitStack(OPND); //初始化OPND栈
InitStack(OPTR); //初始化OPTR栈
Push (OPTR,’#’) ; // 将表达式起始符"#" 压人OPTR栈
cin>>ch;
while(ch!=’#’ | | GetTop(OPTR) !=’#’ ){ //表达式没有扫描完毕或OPTR的栈顶元素不为"# "
if (!In (ch)) {Push (OPND, ch); cin?ch;} //ch不是运算符则进OPND栈
else
switch (Precede (GetTop (OPTR) , ch)){ / /比较OPTR的栈顶元素和ch的 优先级
case’<’:
Push(OPTR,ch);cin>>ch; //当前字符ch压入OPTR栈,读入下一字符ch
break;
case’>’:
Pop(OPTR,theta); //弹出OPTR栈顶的运算符
Pop(OPND,b);Pop(OPND,a); //弹出OPND栈顶的两个运算数
Push (OPND, Operate (a, theta, b·)); / /将运算结果压入OPND栈
break;
case’=’: //OPTR的栈顶元素是"(“且ch是”)"
Pop(OPTR,x) ;cin>>ch; //弹出OPTR栈顶的"(", 读入下一字符ch
break; }//switch
}//while
return GetTop (OPND) ; //OPND栈顶元素即为表达式求值结果
}

算法调用的三个函数需要读者自行补充完成。其中函数In是判定读入的字符ch是否为运算符,Precede 是判定运算符栈的栈顶元素与读入的运算符之间优先关系的函数,Operate为进行二元运算的函数。

二、工具环境

Window10操作系统,Microsoft Visual C++2010学习版 集成开发环境,C语言

三、实验问题

另外需要特别说明的是,上述算法中的操作数只能是一位数,因为这里使用的OPND栈是字符栈,如果要进行多位数的运算,则需要将OPND栈改为数栈,读入的数字字符拼成数之后再入栈。 读者可以改进此算法,使之能完成多位数的运算。

四、实验代码

#include<stdio.h>
#include<stdlib.h>

#define MAXSIZE 100    //顺序栈存储空间的初始分配址
#define OK  1
#define ERROR  0
#define OVERFLOW -2

typedef int  Status;
typedef char SElemType;

typedef struct
{
    char *base;      //栈底指针
    char *top;       //栈顶指针
    int stacksize;   //栈可用的最大容量
}SqStack;

Status InitStack(SqStack *S);//构造一个空栈s
Status Push(SqStack *S,char e);//插入元素e为新的栈顶元素
Status Pop(SqStack *S,char *e);//删除s的栈顶元素,用e返回其值
SElemType GetTop(SqStack S);//返回s的栈顶元素,不修改栈顶指针
Status In(char e);//判断读入字符是否为运算符
SElemType Precede(char a,char b);//比较运算符的优先级,a为纵轴值,b为横轴值
int Operate(int i,char theta,int j);//计算a(theta)b结果
char EvaluateExpression();//算术表达式求值的算符优先算法,设OPTR和OPND分别为运算符栈和操作数栈

int main()
{
    printf("请输入算术表达式,并以#结束(操作数只能是一位数):");
    printf("表达式结果是:%d",EvaluateExpression());
    return 0;
}

Status InitStack(SqStack *S)
{//构造一个空栈s
	S->base=(char *)malloc(MAXSIZE*sizeof(char));//为顺序栈动态分配一个最大容量为MAXSIZE的数组空间
    if(!S->base) exit(OVERFLOW);         //存储分配失败
    S->top=S->base;            //top初始为base,空栈
    S->stacksize=MAXSIZE;     //stacksize置为栈的最大容量MAXSIZE
	return OK;
}

Status Push(SqStack *S,char e)
{//插入元素e为新的栈顶元素
	if(S->top-S->base==S->stacksize) return ERROR;    //栈满
    *S->top++=e;           //元素e压入栈顶,栈顶指针加1
    return OK;
}

Status Pop(SqStack *S,char *e)
{//删除s的栈顶元素,用e返回其值
	if(S->top==S->base) return ERROR;   //栈空
    *e=*--S->top;    //栈顶指针减1,将栈顶元素赋给e
    return OK;
}     

SElemType GetTop(SqStack S)
{//返回s的栈顶元素,不修改栈顶指针
	if(S.top!=S.base)   //栈非空
    return *(S.top-1);   //返回栈顶元素的值,栈顶指针不变
}

Status In(char e) 
{//判断读入字符是否为运算符
	if(e=='+'||e=='-'||e=='*'||e=='/'||e=='('||e==')'||e=='#')
        return OK;//是
    else
        return ERROR;//不是
}

SElemType Precede(char a,char b) 
{//比较运算符的优先级,a为纵轴值,b为横轴值
    char f;
    if(a=='+'||a=='-')
    {
        if(b=='+'||b=='-'||b==')'||b=='#')
        f='>';
        else if(b=='*'||b=='/'||b=='(')
        f='<';
    }
    else if(a=='*'||a=='/')
    {
        if(b=='+'||b=='-'||b=='*'||b=='/'||b==')'||b=='#')
        f='>';
        else if(b=='(')
        f='<';
    }
    else if(a=='(')
    {
        if(b=='+'||b=='-'||b=='*'||b=='/'||b=='(')
        f='<';
        else if(b==')')
        f='=';
    }
    else if(a==')')
    {
        if(b=='+'||b=='-'||b=='*'||b=='/'||b==')'||b=='#')
        f='>';
    }
    else if(a=='#')
    {
        if(b=='+'||b=='-'||b=='*'||b=='/'||b=='(')
        f='<';
        else if(b=='#')
        f='=';
    }
    return f;
}

int Operate(int i,char theta,int j) 
{//计算a(theta)b结果
    int result;
    switch(theta)   {
        case '+': result = i + j; break;
        case '-': result = i - j; break;
        case '*': result = i * j; break;
        case '/': result = i / j; break;
    }
    return result;
}

char EvaluateExpression()
{//算术表达式求值的算符优先算法,设OPTR和OPND分别为运算符栈和操作数栈
    SqStack OPND,OPTR;
    int ch; //把读入的字符转换为整数型,即ASCII表值
    char a,b,theta,x; //ch为当前读入字符, theta为运算符,x仅仅只是变量寄存弹出值,对计算表达式无影响
    InitStack(&OPND); //初始化OPND栈,寄存操作数和运算结果
    InitStack(&OPTR); //初始化OPTR栈,寄存运算符
    Push(&OPTR,'#');
	ch=getchar();
    while(ch!='#'||GetTop(OPTR)!='#')
    {
		printf(" %c\n",ch);
		if(!In(ch))//ch不是运算符则进OPND栈
        {
			ch=ch-48;//数字字符转换为对应整数
			Push(&OPND,ch);
			ch=getchar();
        }
        else
        {
            switch(Precede(GetTop(OPTR),ch))
            {//优先级选择
            case '<':
                Push(&OPTR,ch);
				ch=getchar();
                break;
            case '>':
                Pop(&OPTR,&theta);
                Pop(&OPND,&b);
                Pop(&OPND,&a);
                Push(&OPND,Operate(a,theta,b));
                break;
            case '=':
                Pop(&OPTR,&x);
				ch=getchar();
                break;
            }
        }
    }
	return GetTop(OPND);
}
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-07-26 11:53:50  更:2021-07-26 11:53:54 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年4日历 -2024/4/26 20:44:54-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码