栈和队列——表达式求值大全

article/2025/10/15 22:13:04

表达式求值

一.关于三种表达式的分类

  • 中缀表达式:即我们最为常见的表达式,运算符号位于参与运算的连个操作数中间的表达式称作中缀表达式
  • 前缀表达式:前缀表达式是一种没有括号的算术表达式,与中缀表达式不同的是,其将运算符写在前面,操作数写在后面。为纪念其发明者波兰数学家Jan Lukasiewicz,前缀表达式也称为“波兰式”。例如,- 1 + 2 3,它等价于1-(2+3)。
  • 后缀表达式:指的是不包含括号,运算符放在两个运算对象的后面,所有的计算按运算符出现的顺序,严格从左向右进行(不再考虑运算符的优先规则),后缀表达式也称为逆波兰表达式。

二.表达式的求值算法

1.中缀表达式的求值算法:

假设参与运算的表达式是由+ - * \ ( )这6种符号构成的

规定运算符的优先级:

  • 运算符)的优先级最低,
  • 运算符*,\的优先级相同,运算符+,-的优先级相同,且*,\的优先级大于+,-
  • 运算符(的优先级比较特殊,当(作为入栈元素时,它的优先级最大,即无条件入栈;而当(作为栈顶元素时,它的优先级最小,即除运算符)以外的所有运算符无条件入栈
  • 当栈顶元素为(,入栈元素为)时,两运算符在符号栈中相抵消。

假设θ1是栈顶元素,θ2是入栈元素,那么具体的运算符优先级关系比较可由下表体现:
在这里插入图片描述
在求值算法中,我们需要用到两个栈来帮助计算:
其中一个称为运算数栈,用来存放参与运算的数,简称OPND(operand)
另一个称为运算符栈,用来存放参与运算的运算符,简称OPTR(operator)

正式算法描述如下:

首先初始化两个栈,然后从中缀表达式按照从左往右的顺序去取符号c,

如果取到的是运算数,则将c放入OPND中入栈;
如果取到的是运算符,则加以判断:

  • 如果OPTR栈空,则将c入栈OPTR
  • 如果c的优先级大于OPTR的栈顶元素,则将c入栈OPTR
  • 如果c的优先级小于OPTR的栈顶元素,则从栈OPTR中以此出栈两个运算数n1,n2,做n2 c n1的运算后将得到的结果n入栈OPND
  • ‘(’和’)‘的情况可特殊处理,如果栈顶元素和入栈元素分别为’(‘和’)‘时,相消即可

当操作数栈空并且表达式被全部读取完毕时,计算结束,可以获得最终求值结果

下面列出算法代码:

关于栈的定义和基本操作:

//栈的定义 
typedef struct stack
{char elements[100];int top;int size;
}stack;//栈的基本操作 
void InitStack(stack *s)
{s->top=0;s->size=0;
}void Push(stack *s,char c)
{s->elements[s->top++]=c;s->size++;
}void Pop(stack *s,char *c)
{*c=s->elements[--s->top];s->size--;
}void Top(stack *s,char *c)
{*c=s->elements[s->top-1];
}int isEmpty(stack *s)
{if(s->top==0)return 1;else return 0;
}

求值算法:

//中缀表达式求值算法 
int Calculate_InfixExpression(char *s,int length)
{stack OPND,OPTR;InitStack(&OPND);InitStack(&OPTR);int i=0;char a,b,c,t,result;while(s[i]!=0||!isEmpty(&OPTR)){c=s[i++];if(c>='0'&&c<='9'){Push(&OPND,c);}else{Top(&OPTR,&t);if(isEmpty(&OPTR)) 	Push(&OPTR,c);else{switch(compare(t,c)){case -1: {Push(&OPTR,c);break;}case 1:{Pop(&OPTR,&t);Pop(&OPND,&a);Pop(&OPND,&b);Push(&OPND,opreate(a,b,t));i--;break;}case 0:{Pop(&OPTR,&t);break;}		}}}}	Top(&OPND,&result);return result-'0';
}

补充算法中的两个函数,运算符优先级的比较函数和操作数的计算函数:

//运算符比较函数 
int compare(char c1, char c2)
{if(c1=='('&&c2==')') return 0;else if(c1=='('||c2=='(') return -1;else if(c1=='*'||c1=='/') return 1;else if(c1=='+'||c1=='-'){if(c2=='*'||c2=='/') return -1;else return 1;}
}//运算操作函数
char opreate(char n,char m,char c) 
{int a=n-'0';int b=m-'0';switch(c){case '+':return b+a+'0';case '-':return b-a+'0';case '*':return b*a+'0';case '/':return b/a+'0';}
}

主函数调用及运算效果:

main()
{char s[]="3+2*(7-2)+(2+1)*3";int result = Calculate_InfixExpression(s,strlen(s));printf("%s = %d",s,result);
}

在这里插入图片描述

2.后缀表达式的求值算法

后缀表达式的求值算法比较简单,利用单独的栈即可完成计算:
从左向右扫描后缀表达式:

  • 如果遇到的是运算数,则入栈
  • 如果遇到的是运算符o,则从栈中依次出栈两个元素:a,b;将b o a 的结果入栈
  • 最终当栈中只剩一个元素时,即为最后所求结果

c语言的算法实现,目的是表达算法逻辑,所以为了简单,只支持单步操作结果在255以内的计算,原因是栈的元素类型是char

int calculate(char *src) 
{stack s;InitStack(&s);int length=strlen(src),i=0;char c,a,b,result;for(i=0;i<length;i++){c=src[i];if(c>='0'&&c<='9'){Push(&s,c);}else{Pop(&s,&a);Pop(&s,&b);Push(&s,opreate(a,b,c));}}if(!isEmpty(&s)) Pop(&s,&result);return result-'0';}

三.中缀表达式到后缀表达式的转换

1.利用栈进行转换的算法

算法描述如下:
我们借助一个操作符栈来进行转换运算,并将转换结果存入一个结果队列当中
从左到右按顺序扫描中缀表达式:

  • 如果扫描到的是运算数,则将运算数直接存入结果队列
  • 如果扫描到的是’(',则直接将其入栈,入栈后其拥有最低的优先级
  • 如果扫描到的是’)‘,则将栈中存在于’('之前的所有运算符依次出栈并入队,‘('也出栈但不入队
  • 如果遇到的是一般运算符,则将其与栈顶运算符比较:如果其优先级高于栈顶运算符的优先级,则将其入栈;否则将栈顶运算符出栈并入队,直到栈顶运算符优先级小于该运算符为止
  • 当扫描结束时,如果运算符栈不为空,则将其中元素全部出栈并入队

最终结果队列中存放的就是转换后的后缀表达式

给出后缀表达式算法的c语言实现:

char *conversion(char * src)
{stack s;InitStack(&s);int length=strlen(src),i=0,j=0,k;char c,t,*dst=(char *)malloc(sizeof(char)*length);for(i=0;i<length;i++){c=src[i];if(c>='0'&&c<='9'){dst[j++]=c;}else if(c=='('){Push(&s,c);}else if(c==')'){Top(&s,&t);while(t!='('){Pop(&s,&t);if(t!='(')  dst[j++]=t;else break;	}}else{if(isEmpty(&s)){Push(&s,c);}else{Top(&s,&t);switch(compare(t,c)){case -1: Push(&s,c);break;case 1: {while(compare(t,c)==1){Pop(&s,&t);dst[j++]=t;if(isEmpty(&s)) break;Top(&s,&t);}Push(&s,c);	}break;}}}}while(!isEmpty(&s)){Pop(&s,&t);dst[j++]=t;}return dst;
}main()
{char * src="2+3*4+(6*8+7)*5";char *dst=conversion(src);printf("后缀表达式为:%s ",dst);} 

运行结果如下:
在这里插入图片描述


http://chatgpt.dhexx.cn/article/J5lPGCDP.shtml

相关文章

栈与队列-

基础 stl中栈和队列不是容器&#xff0c;而是容器适配器。它们提供接口&#xff0c;由其他容器实现。 20. 有效的括号 给定一个只包括 ‘(’&#xff0c;‘)’&#xff0c;‘{’&#xff0c;‘}’&#xff0c;‘[’&#xff0c;‘]’ 的字符串 s &#xff0c;判断字符串是否…

数据结构----栈和队列

xdm这玩意我不会导入&#xff0c;只能截图了。 目录 栈篇 1.1栈 1.2.栈操作数据元素的两种动作&#xff1a; 2.代码实现 2.1初始化和销毁 2.2插入 2.3删除和判空 2.4返回栈顶值,计算栈长 队列篇 3.1队列 4.代码实现 4.1初始化和销毁和判空 4.2入列 4.3出列 4.4…

栈(Stack)和队列(Queue)详解

1. 什么是栈&#xff0c;栈存储结构详解 同顺序表和链表一样&#xff0c;栈也是用来存储逻辑关系为 “一对一” 数据的线性存储结构&#xff0c;如图 1 所示。 图 1 栈存储结构示意图 从图 1 我们看到&#xff0c;栈存储结构与之前所学的线性存储结构有所差异&#xff0c;这缘…

栈和队列--栈

1、顺序栈 一组地址连续的存储单元加一个标识栈顶元素的指针。 #define MaxSize 50 //定义栈中最大元素个数 typedef struct{ ElemType data[MaxSize];//存放栈中的元素int Top;//栈顶指针 }SqStack;栈空&#xff1a;s.top-1 栈满&#xff1a;s.topMaxSize-1 栈长&#xff…

什么是栈?什么是队列?栈与队列的特点

栈 栈&#xff08;Stack&#xff09;是限定在仅在表尾插入的线性表。 因此对于栈来说&#xff0c;表尾具有特殊的含义。我们把表尾称作栈顶&#xff08;top&#xff09;&#xff0c;把表头称作栈底&#xff08;bottom&#xff09;。不含元素的栈称为空栈。 想象一下进栈的顺序…

栈和队列——相关例题

文章目录 一、栈例题——模拟栈具体实现1. 模板1.1 代码注解1.2 实现代码 2. STL2.1 代码注解2.2 实现代码 二、栈例题——表达式求值具体实现1. 实现思路2. 代码注解3. 实现代码 三、单调栈例题——单调栈具体实现1. 实现思路2. 实现代码 四、队列例题——模拟队列具体实现1. …

【栈和队列】

大家好,这里是针对栈和队列做的一些总结归类,主要是介绍了栈和队列的相关操作,特意整理出来一篇博客供我们一起复习和学习,如果文章中有理解不当的地方,还希望朋友们在评论区指出,我们相互学习,共同进步! 文章目录 一&#xff1a;栈1.1 栈的概念及结构1.2 栈的实现1.3 典型案例…

栈、队列

顺序栈&#xff0c;即栈的顺序存储结构是利用一组地址连续的存储单元依次存放自栈底到栈顶的数据元素&#xff0c;同时附设指针top指示栈项元素在顺序栈中的位置。通常的习惯做法是以top&#xff1d;0表示空栈&#xff0c;鉴于C语言中数组的下标约定从0开始&#xff0c;则当以C…

栈、队列、数组

栈 定义 #include <stdio.h>/* 栈只允许在栈顶插入删除操作的线性表Last Insert First Out. */// 顺序栈#define MaxSize 10typedef struct {int data[MaxSize]; // 静态数组存放栈元素int top; // 栈顶指针 } SqStack; 栈顶指针指向栈顶元素的栈 空为-1 // 栈顶指针指…

使用SQL进行两个表关联查询(inner)

结果显示 公司类型表 公司表 实现方式 SELECTt_company.id,cName, typeName, cDescribe, t_company.modifyTime, t_company.createTime FROMt_company INNER JOIN t_company_type ON t_company.cType t_company_type.id代码解析 SELECT 显示字段,如果两个表都有字段,则需要…

sql进行两个关联表,根据其中一个表的一个属性进行条件查询查询

我最近遇到了表的查询,但是通过查询发现,网上的sql的大神,写的文章到底是什么玩意? 我打算自己写一个sql专栏,特意讲解sql的使用,来帮助大家 这篇文章技术指导为sql进行两个关联表,根据其中一个表的一个属性进行条件查询查询 假设只有两张表,其中一张表最后一个外键连…

SQL关联查询详解,SQL JOIN详解

关联查询&#xff0c;也称为多表查询&#xff0c;指两个或更多个表一起完成查询操作。 前提条件&#xff1a;这些一起查询的表之间是有关系的&#xff08;一对一、一对多&#xff09;&#xff0c;它们之间一定是有关联字段&#xff0c;这个关联字段可能建立了外键&#xff0c;也…

SQL-多表关联查询详解

为了在工作中能更顺利的使用多表关联查询&#xff0c;今天这篇博客就写这个内容了。 在讲解多表关联查询之前&#xff0c;先生成测试表。 登录scott用户&#xff0c;运行以下语句生成测试表。 create table ex1 as select * from emp; create table ex2 as select * from dept…

Mysql如何对两张表的相同字段,同时查询两张数据表

前言 假设现在有两张数据表 表1如下&#xff1a; 表2如下&#xff1a; 表1和表2同时都再mysql的情况下&#xff0c;只有他们的uuid是一样的&#xff0c;其他字段信息不同&#xff0c;现在需要用sql语句根据uuid&#xff0c;同时将符合要求的数据查询出来&#xff0c;怎么做呢&…

SQL- join多表关联

一、SQL 连接(JOIN) 1、笛卡尔积 &#xff08;1&#xff09;当多张表进行连接查询&#xff0c;没有任何条件限制的时候&#xff0c;最终查询结果条数&#xff0c;是多张表条数的乘积 如A表15条&#xff08;行&#xff09;数据&#xff0c;B表20条&#xff08;行&#xff09;…

SQL语言多表关联查询

新建两张表&#xff1a; 表1&#xff1a;student 截图如下&#xff1a; 表2&#xff1a;course 截图如下&#xff1a; &#xff08;此时这样建表只是为了演示连接SQL语句&#xff0c;当然实际开发中我们不会这样建表&#xff0c;实际开发中这两个表会有自己不同的主键。&…

[转载]静息态fMRI、DTI、VBM

[转载]静息态fMRI、DTI、VBM (2014-06-19 19:00:15) 转载▼ 标签&#xff1a; 转载 分类&#xff1a; fMRI-EEG 原文地址&#xff1a;静息态fMRI、DTI、VBM作者&#xff1a;426l 一、 简介 1、静息态fMRI数据处理学习内容 BOLD-fMRI技术自1990年发明至今&#xff0c;已经成…

用FSL进行VBM统计分析

用FSL进行VBM统计分析 总体步骤概览1.准备数据1.1 T1数据格式1.2 Template_list查看数据 2.剥头皮&#xff1a;fslvbm_1_bet3.数据分割生成模板&#xff1a;fslvbm_2_template4.后处理&#xff08;标准化、调制、平滑&#xff09;&#xff1a;fslvbm_3_proc5.统计检验5.2查看结…

[spm操作] VBM分析中,modulation的作用

本帖作为 《用Matlab和SPM批量处理被试的经验总结》 的一部分 目录贴请见 http://home.52brain.com/forum.ph ... 1&extra#pid158525 在VBM分析中&#xff0c;通常都有一个modulation的选项&#xff0c;有些滴友对这个步骤的作用有点不太理解。 我先举一个例子&#xff…