使用栈实现表达式求值

使用栈实现表达式求值任何一个表达式都是由操作数,运算符,界限符组成的。操作数即是参加运算的数值或者变量,运算符则是加减乘除等组成,为简单起见,这里只实现加减乘除的运算,而常见的界限符则是左右括号和终止符。在运算过程中,要判断两个先后出现的运算符之间的优先顺序。为了实现算法,设置两个工作栈:用于存储运算符的栈opter,以及用于存储操作数及中间结果的栈opval。算法基本思想如下:(1)首先将操作数栈opv

大家好,又见面了,我是你们的朋友全栈君。

为了实现用栈计算算数表达式的值,需设置两个工作栈:用于存储运算符的栈opter,以及用于存储操作数及中间结果的栈opval。

算法基本思想如下:

(1)首先将操作数栈opval设为空栈,而将’#’作为运算符栈opter的栈底元素,这样的目的是判断表达式是否求值完毕。

(2)依次读入表达式的每个字符,表达式须以’#’结尾,若是操作数则入栈opval,若是运算符,则将此运算符c与opter的栈顶元素top比较优先级后执行相应的操作,(具体操作如下:(i)若top的优先级小于c,即top<c,则将c直接入栈opter,并读入下一字符赋值给c;(ii)若top的优先级等于c,即top=c,则弹出opter的栈顶元素,并读入下一字符赋值给c,这一步目的是进行括号操作;(iii)若top优先级高于c,即top>c,则表明可以计算,此时弹出opval的栈顶两个元素,并且弹出opter栈顶的的运算符,计算后将结果放入占opval中。)直至opter的栈顶元素和当前读入的字符均为’#’,此时求值结束。

算符间的优先关系如下表所示:

使用栈实现表达式求值

表中需要注意的是θ1为opter的栈顶元素,θ2位从表达式中读取的操作符,此优先级表可以用二维数组实现,具体见代码(表来源:严蔚敏《数据结构》)。

具体代码如下:

#include<iostream>     //输入的表达式要以'#'结尾,如‘5+6*3/(3-1)#’
#include<cstring>
#include<cstdio>
#include<cctype>
#include<stack>
using namespace std;

stack<char> opter;    //运算符栈
stack<double> opval;  //操作数栈

int getIndex(char theta)   //获取theta所对应的索引
{
	int index = 0;
	switch (theta)
	{
	case '+':
		index = 0;
		break;
	case '-':
		index = 1;
		break;
	case '*':
		index = 2;
		break;
	case '/':
		index = 3;
		break;
	case '(':
		index = 4;
		break;
	case ')':
		index = 5;
		break;
	case '#':
		index = 6;
	default:break;
	}
	return index;
}

char getPriority(char theta1, char theta2)   //获取theta1与theta2之间的优先级
{
	const char priority[][7] =     //算符间的优先级关系
	{
		{ '>','>','<','<','<','>','>' },
		{ '>','>','<','<','<','>','>' },
		{ '>','>','>','>','<','>','>' },
		{ '>','>','>','>','<','>','>' },
		{ '<','<','<','<','<','=','0' },
		{ '>','>','>','>','0','>','>' },
		{ '<','<','<','<','<','0','=' },
	};

	int index1 = getIndex(theta1);
	int index2 = getIndex(theta2);
	return priority[index1][index2];
}

double calculate(double b, char theta, double a)   //计算b theta a
{
	switch (theta)
	{
	case '+':
		return b + a;
	case '-':
		return b - a;
	case '*':
		return b * a;
	case '/':
		return b / a;
	default:
		break;
	}
}

double getAnswer()   //表达式求值
{
	opter.push('#');      //首先将'#'入栈opter
	int counter = 0;      //添加变量counter表示有多少个数字相继入栈,实现多位数的四则运算
	char c = getchar();
	while (c != '#' || opter.top() != '#')   //终止条件
	{
		if (isdigit(c))   //如果c在'0'~'9'之间
		{
			if (counter == 1)   //counter==1表示上一字符也是数字,所以要合并,比如12*12,要算12,而不是单独的1和2
			{
				double t = opval.top();
				opval.pop();
				opval.push(t * 10 + (c - '0'));
				counter = 1;
			}
			else
			{
				opval.push(c - '0');     //将c对应的数值入栈opval
				counter++;
			}
			c = getchar();
		}
		else
		{
			counter = 0;   //counter置零
			switch (getPriority(opter.top(), c))   //获取运算符栈opter栈顶元素与c之间的优先级,用'>','<','='表示
			{
			case '<':               //<则将c入栈opter
				opter.push(c);
				c = getchar();
				break;
			case '=':               //=将opter栈顶元素弹出,用于括号的处理
				opter.pop();
				c = getchar();
				break;
			case '>':               //>则计算
				char theta = opter.top();
				opter.pop();
				double a = opval.top();
				opval.pop();
				double b = opval.top();
				opval.pop();
				opval.push(calculate(b, theta, a));
			}
		}
	}
	return opval.top();   //返回opval栈顶元素的值
}

int main()
{
	//freopen("test.txt", "r", stdin);
	int t;     // 需要计算的表达式的个数
	cin >> t;
	getchar();
	while (t--)
	{
		while (!opter.empty())opter.pop();
		while (!opval.empty())opval.pop();
		double ans = getAnswer();
		cout << ans << endl<< endl;
		getchar();
	}
	return 0;
}

结果:

使用栈实现表达式求值

使用栈实现表达式求值

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/148806.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • docker(4)解决pull镜像速度缓慢「建议收藏」

    docker(4)解决pull镜像速度缓慢「建议收藏」前言上一篇讲到pull镜像,但是pull镜像的时候下拉的速度实在感人,有什么解决办法吗?我们只需将docker镜像源修改为国内的将docker镜像源修改为国内的:在/etc/docker/d

    2022年7月28日
    45
  • java oracle分页查询语句_oracle 分页语句

    java oracle分页查询语句_oracle 分页语句通过Debug调试,发现第一页查询到的数据没有问题,第二页时,查不到数据!第一页时,控制台打印的sql语句:SELECTOBJ_NAME,OBJ_ATTRIBUTE_NAME,ATTRIBUTE_TYPE,DES,STS,PRIORITYFROM(SELECTm.*,rownumrow_idFROM(SELECTOBJ_NAME,OBJ_ATTRIBUTE_NAME,ATT…

    2022年5月28日
    34
  • java类加载过程详解_java三个类加载器

    java类加载过程详解_java三个类加载器朋友给我发了一道有意思的题目,如下为什么用.class的方式加载类和以Class.forName()的方式加载的结果不同呢,原因很简单,就是类加载过程的不同。这就扯到基础理解上了,就是Java是如何加载一个类的呢?上图是我绘制的整个Java类加载过程。首先是编译期,将Java源文件也就是敲好的代码通过编译,转换成.class文件,也就是字节码文件(byte),然后经过传输传…

    2022年8月11日
    7
  • JNZ是什么指令_pushf指令

    JNZ是什么指令_pushf指令书中127页有这么一段,movdx,0x1f7.waits:inal,dxandal,0x88cmpal,0x08jnz.waits最后一句的jnz完全可以用jne代替,那jnz/jne,jz/je区别到底是什么呢?刚想到这个问题时候我有点懵,明明都是由ZF标志位决定的啊,有啥不一样啊QAQjnz指令,if(ZF!=0)则跳转,在

    2025年8月8日
    3
  • java fork join_java8学习:ForkJoin[通俗易懂]

    java fork join_java8学习:ForkJoin[通俗易懂]先实现一下,再来说原理还是实现1到一千万的累加和publicclassForkJoinImplextendsjava.util.concurrent.RecursiveTask{//临界值,就是结束值减开始值的结果如果小于这个值那么就不拆分了,大于这个值才会拆分privatefinalintMEDIAN_NUM=100000;//从多少计算privateintstart_n…

    2022年9月20日
    4
  • flag_activity_new_task 简单_activity启动流程图解

    flag_activity_new_task 简单_activity启动流程图解当在一个的activity以FLAG_ACTIVITY_NEW_TASK的方式启动另一个已经启动的activity时,需要设置intent.addCategory(Intent.CATEGORY_LAUNCHER);intent.setAction(Intent.ACTION_MAIN);否则将要打开的activity会重走一遍onCreate(),加上之后会直接调用之前的acti

    2022年9月28日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号